clr

2025-10-31T20:32:29.095129Z

The quoted thread is speculating about whether we can give special treatment to java.lang.Object methods in method resolution. Does ClojureCLR's reflector/compiler give any special treatment to System.Object? I noticed that #(.GetType %) does not reflect while #(.getClass %) does.

dmiller 2025-11-01T20:31:53.738059Z

I'm not quite sure what you are asking here. Contrary to your assertion, I find that #(.GetType %) does reflect:

Clojure 1.12.3-alpha4
user=> (set! *warn-on-reflection* true)
true
user=>  (def f #(.GetType %))
Reflection warning, NO_SOURCE_PATH:1:10 - reference to field/property GetType can't be resolved (target class is unknown).
#'user/f
ClojureCLR, you might be aware, does handle the generated code for the anonymous function shown in a manner unlike ClojureJVM. Rather than code-gen'ing a call to a clojure.lang.Reflect method to do reflection at call time to determine what to call, ClojureCLR uses a Dynamic Language Runtime (DLR) callsite to encode the getMember dynamic operation. That uses a binder to do the lookup of member GetType. In this case, the binder is ClojureGetZeroArityMemberBinder which is designed exclusively for the case of a dynamic (i.e., requiring reflection) lookup of a type member in a no-args situation. This binder looks for a field, a property, and a zero-arity method, in that order. In the situation you outline, assuming a renaming of the Foo field to get an overlap with the instance method Type.GetType, we have
user=> (deftype Foo [GetType])
user.Foo
user=> (#(.GetType %) (->Foo 1))
Reflection warning, NO_SOURCE_PATH:1:4 - reference to field/property GetType can't be resolved (target class is unknown).
1
We note here from the return value 1 that the field GetType in class Foo was used. This confirms the priority ordering of field > property > method. Of course, a type hint does the correct thing. Generally, I would recommend against naming a field the same name as a zero-arity method in a base class, but that's just me. If you try it in C#, you will get a warning about overriding, and a suggestion to use the new keyword to indicate your intent. But also C# does not have the problem of ambiguity of reference:
foo.GetType   // obviously a reference to the field
foo.GetTYpe() // obviously a method call
We can unambiguously refer to the method by direct use of a variant syntax for .:
user=> (#(. % (GetType )) (->Foo 1))
Reflection warning, NO_SOURCE_PATH:1:4 - call to method GetType can't be resolved (target class is unknown).
user.Foo
The parens around GetType designate a method call. However, and perhaps the point of your question, ClojureCLR does not privilege Object in the analysis; reflection occurs because of the lack of a type hint on the target.

dmiller 2025-11-01T20:53:42.513339Z

At any rate, if one were to give special treatment to Object, you woul dhave to tpe-hint to get to the field in question. Which is more likely? You call .getClass meaning Class.getClass (or equiv Type.GetType), or you want to get the field?

2025-11-03T17:30:30.298889Z

1. Yes, sorry I think I inferred that from (.GetType 1) not reflecting that #(.GetType %) didn't. (.getClass 1) reflects in JVM. 2. looks like there's a major difference in the reflector between jvm and clr. jvm always chooses the method.

;; jvm
user=> (deftype Foo [getClass])
user.Foo
user=> (.getClass (#(->Foo 1)))
Reflection warning, NO_SOURCE_PATH:1:1 - reference to field getClass can't be resolved.
user.Foo

;; clr
user=> (deftype Foo [GetType])
user.Foo
user=> (.GetType (#(->Foo 1)))
Reflection warning, NO_SOURCE_PATH:1:2 - reference to field/property GetType can't be resolved (target class is unknown).
1

2025-11-03T17:41:41.569069Z

How would you call the method in this CLR example?

user=> (definterface IFoo (MethodName []))    
user.IFoo
user=> (deftype Foo [MethodName] IFoo (MethodName [_] :method))
user.Foo
user=> (.MethodName (->Foo :field))
:field
EDIT: Ah in this case you'd use IFoo as the type hint.

✅ 1
dmiller 2025-11-03T22:14:53.342519Z

Regarding your .getClass / .GetType example in the initial post, I'll have to take a look at that. I'm sure there are examples where there is disagreement between ClojureJVM and ClojureCLR. The type systems are not in complete agreement. The question is whether the disagreements are based in those differences or accidental. What I started working on last week was a detailed analysis of these issues. I suspect there are some corners of the type system where ClojureCLR even disagrees with itself. The analysis for member resolution during compilation might not (likely is not) identical to the analysis that takes place during runtime when reflection is required. The latter is based on the DLR callsite mechanism and was written in consultation with IronPython/IronRuby coding. Those were the only examples available. Do you know of any good writeup of the actual algorithm used in ClojureJVM for reflection? How it decides field vs method is reasonably direct. How it handles method overloads, parameter-to-argument type matching, subsumption, etc., is buried in code. I'm trying to find a succinct description reasoning from first principles. (Not being part of the official documentation, can one presume it is an implementation detail, not to be relied upon and subject to change?)

dmiller 2025-11-03T23:44:02.667989Z

regarding

;; jvm
user=> (deftype Foo [getClass])
user.Foo
user=> (.getClass (#(->Foo 1)))
Reflection warning, NO_SOURCE_PATH:1:1 - reference to field getClass can't be resolved.
user.Foo
the parsing of the host expression (.getClass ...) leads to the creation of an AST node of type InstanceFieldExpr -- a bit of a misnomer since this could be a method call. There is a parameter fieldRequired in the constructor that inits a field of the same name -- for this call it is false. (It is only true when we have something like (.-name ...) ). Because the target type is unknown, a reflection call is code-gen'd. In this case to Reflector.invokeNoArgInstanceMember. In that code, we find
List meths = getMethods(c, 0, name, false);
		if(meths.size() > 0)
			return invokeMatchingMethod(name, meths, target, RT.EMPTY_ARRAY);
		else
			return getInstanceField(target, name);
This code prioritizes method matches over instance fields. As I noted previously, I had coded ClojureCLR to prioritize field > property > method. I'm sure I had a reason. In the dim recesses of my memory, I think my decision had to do with incorporating properties. This was before the prefix-hyphen-forces-field-interpretation convention was established. There was already a way to force choosing method over field: use (. target (method-name)) syntax. I was struggling with properties, etc. I might even have missed a change of algorithm when prefix-hyphen was introduced. I doubt it is worth changing things now. (If I could do so without really screwing something up.) I'm more concerned with making sure that compile-time member selection matches reflection-time member selection.

2025-11-04T03:57:37.790859Z

I think the introduction of :param-tags had a lot of surrounding design discussion to ensure it was backwards compatible. See Alex Miller's conj keynote.

2025-11-04T03:58:05.168839Z

Thanks for the context, I forgot about the . syntax to disambiguate.

2025-11-04T03:58:22.569659Z

And so far I have found no evidence that the compiler and reflector disagree on CLR.

2025-11-04T03:59:46.683679Z

I'm actually porting some internal parts of the CLR reflector to a .cljc file that already has parts of the .clj reflector. That would be a nice way to see the differences.

dmiller 2025-11-01T02:59:58.339009Z

I don't think any s pecial consideration is given, but I'll take a closer look shortly to make sure. Your question coincides with my review of reflection and DLR-based callsites, so the timing is serendipitous.