Clojure

Accessing Java property starting with _ has issues in 1.4

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Minor Minor
  • Resolution: Declined
  • Affects Version/s: Release 1.4
  • Fix Version/s: None
  • Component/s: None
  • Labels:
  • Approval:
    Triaged

Description

When attempting to use interop syntax with symbols which aren't legal Java names (such as deleted?), the names are mangled a bit. That's necessary, of course, and the method of munging can be internal to the compiler. However, the behavior when munging changed a little between 1.3 and 1.4 beta1. Obviously the specifics of munging are something I should avoid relying on, but the way it changed looks like an accident or a bug even so.

The use-case I ran into is that defrecords contain a field named __meta for tracking their metadata. In both 1.3 and 1.4 you can get at that field with (. record __meta), which avoids munging. But on 1.3 (. record --meta) also accesses it (translating each - to a _), while on 1.4 (. record -meta) works and (. record --meta) doesn't.

Actually, looking at line 883 of Compiler.java, it looks like this may be related to the (. foo -property) syntax ported from CLJS, and indeed (. record ---meta) works, I guess by reducing to an "old style" (. record --meta). So that clears up why --meta fails: it's looking for __meta. I'm still not clear on why (. record -meta) works, though.

So it looks like the - prefix for properties is not 100% backwards-compatible like it seemed to be. Is this an issue we need to fix, or is the recommendation simply to never have fields that start with - or _?

Activity

Hide
Fogus added a comment - - edited

Is this a general problem with fields starting with _ or just fields named __meta as in (defrecord [__meta] ...)

Show
Fogus added a comment - - edited Is this a general problem with fields starting with _ or just fields named __meta as in (defrecord [__meta] ...)
Hide
Alan Malloy added a comment -

It's a general issue. (defrecord [__meta]) actually breaks immediately, because the record mechanism itself generates a field named __meta, but any field named with a - or _ prefix has this issue.

user=> (defrecord Foo [-blah])
user.Foo
user=> (.-blah (Foo. 1))
IllegalArgumentException No matching field found: blah for class user.Foo clojure.lang.Reflector.getInstanceField (Reflector.java:289)

Show
Alan Malloy added a comment - It's a general issue. (defrecord [__meta]) actually breaks immediately, because the record mechanism itself generates a field named __meta, but any field named with a - or _ prefix has this issue. user=> (defrecord Foo [-blah]) user.Foo user=> (.-blah (Foo. 1)) IllegalArgumentException No matching field found: blah for class user.Foo clojure.lang.Reflector.getInstanceField (Reflector.java:289)
Hide
Alex Miller added a comment -

The . syntax is interop and should always be used with Java-style field names. If other things work, that's undocumented and subject to change. You can access fields by using either . (which can also refer to methods) or .- (for field access only if there is ambiguity) - also see https://clojure.org/reference/java_interop.

The munging style for internal record field names should be considered an implementation detail, although maybe one it's useful to know about.

For the internal _meta example, which will become a Java field named "_meta":

;; Things that should (and do) work for interop:
(.__meta foo)
(. foo __meta)
(.-__meta foo)
(. foo -__meta)

Anything with --meta is undefined and unsupported.

For a field that starts with -, the following should be expected to work for the munged name ("_blah"):

(defrecord R [-blah])
(def r (->R 10))

(._blah r)
(. r _blah)
(.-_blah r)
(. r -_blah)

Anything Java interop stuff with -blah is undefined and unsupported.

Show
Alex Miller added a comment - The . syntax is interop and should always be used with Java-style field names. If other things work, that's undocumented and subject to change. You can access fields by using either . (which can also refer to methods) or .- (for field access only if there is ambiguity) - also see https://clojure.org/reference/java_interop. The munging style for internal record field names should be considered an implementation detail, although maybe one it's useful to know about. For the internal _meta example, which will become a Java field named "_meta":
;; Things that should (and do) work for interop:
(.__meta foo)
(. foo __meta)
(.-__meta foo)
(. foo -__meta)
Anything with --meta is undefined and unsupported. For a field that starts with -, the following should be expected to work for the munged name ("_blah"):
(defrecord R [-blah])
(def r (->R 10))

(._blah r)
(. r _blah)
(.-_blah r)
(. r -_blah)
Anything Java interop stuff with -blah is undefined and unsupported.

People

Vote (0)
Watch (2)

Dates

  • Created:
    Updated:
    Resolved: