# Imports as completion candidates for hash-langs

**URL:** <https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511>\
**Category:** General\
**Created:** [November 17, 2023, 2:19pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511 "2023-11-17T14:19:04Z")\
**Posts on this page:** 17\
**Page:** 2

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [November 21, 2023, 7:04pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/21 "2023-11-21T19:04:01Z")

</div>

One challenge I realize now, having written that patch, is that there's no binding arrow because `max` is not in fact provided by `rhombus` (only `math` is). So to make go-to-definition work right, it now has to handle the case where there's no binding location but you want to go to the definition in another file anyway.

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [November 21, 2023, 7:59pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/22 "2023-11-21T19:59:44Z")

</div>

Previously the concept has been that there may exist compound identifiers (made at least partially from two or more other pieces of syntax). These are real identifiers -- they get binding arrows, `identifier-binding` knows their nominal and transitive source, and so on.

To reveal the sources of their components, they may have a syntax-property like `sub-range-binders` or `import-or-export-prefix-ranges`. This has covered things like struct predicates/accessors/setters, prefixed exports, and so on.

For example the struct accessor `exn-message` is a real identifier. A stx prop reveals the `exn` and `message` source pieces. Likewise ids created by `prefix-out`.

* * *

I'm not sure how to understand something like `math.min` where (IIUC):

- `math` is real and comes from rhombus -- but...
- `math.min` isn't real
- `min` isn't real even though it comes nominally from rhombus and ultimately from racket/base

I'm not claiming this is bad or wrong. I just don't understand what it even means, yet.

So I'm not sure what to propose to do about it, yet.

For now I'm reduced to pointing out the status quo techniques and wondering why they can't be used.

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [November 21, 2023, 8:08pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/23 "2023-11-21T20:08:49Z")

</div>

I think the way to understand `math.min` is that it is really `(math (op |.| min))` (taking a few liberties with the shrubbery syntax). So `math` is real, and it's a macro that looks at its input and decides, based on parsing that input, that it wants to expand to `min` (the identifier defined in `racket/base`).

So there isn't really any `math.min` identifier anywhere, compound or not -- that's not how that notation `read`s.

This is, as you note, quite unlike how eg `exn-message` works, or how dotted identifiers work in `syntax-parse`, where it binds identifiers for all of the various dotted forms and they are just regular Racket identifiers.

I think `min` is real, although there are _two_ `min`s -- the name after the dot and the identifier in the expanded code, which happen to have the same spelling. I think the tools we have are enough to help tools find `min` appropriately, although as I mentioned some adjustments seem required.

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [November 22, 2023, 8:53pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/24 "2023-11-22T20:53:40Z")

</div>

I believe it's fine if `math.min` doesn't exist, provided both `math` and `min` do. (In some ways that's cleaner than the composite `math.min` and needing stx props to recover the pieces.)

The interpretation that `math` and `min` are two distinct identifiers should be OK provided:

1. check-syntax draws arrows for both (currently it doesn't for `min`, making it "unreal" for various purposes).

2. The syntax at the binding/definition end of the arrow can be given to `identifier-binding` and it returns meaningful "from-xxx" and "nominal-from-xxx" values. (Which can be used when check-syntax-ing other sources, transitively... until the ultimate definition site is reached.)

Whenever @robby might have time to help figure out 1, I could see whether 2 is working out, too. (Which might lead back to the hitch that `min` isn't exported in the usual/old ways... but one step at a time, I guess.)

---

<div class="post-metadata">

**Author:** ![robby](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/robby/32/7_2.png) [@robby](https://racket.discourse.group/u/robby)\
**Post date:** [November 22, 2023, 9:28pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/25 "2023-11-22T21:28:14Z")

</div>

@samth offered some code similar to this; here's a variation I wanted to ask about:

```scheme
#lang racket
(define-syntax (scope stx)
  (syntax-case stx (math string)
    [(_ math id) (with-syntax ([i (syntax-e #'id)])
                   #'(let () (local-require (only-in racket/math i)) i))]))
(scope math pi)

```

With a definition like `scope`, I don't see how check syntax is going to draw an arrow without some changes. Why is `i` put into the let and not `id`? There is also no place to put an arrow that goes to `racket/math` (as I suppose the actual occurrence of `racket/math` is elsewhere and this one is just `math`). Do we need an actual arrow, or just an annotation that `pi` came from the `racket/math` library?

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [November 22, 2023, 9:31pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/26 "2023-11-22T21:31:51Z")

</div>

I think the question of where to put the other end of the arrow is the important one for @greghendershott's point 1. The patch I linked to gets some information so that DrRacket knows that `min` comes from `racket/math` and can point to the documentation (but without the arrow it won't jump to the definition). Strangely that doesn't work for `pi` though.

As to why `i` and not `id`, it's because otherwise there are extra scopes on `id` and the macro doesn't work.

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [November 22, 2023, 10:04pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/27 "2023-11-22T22:04:00Z")

</div>

Here's probably a better example to start from. This highlights/links to documentation for both `sqr` and `pi`, and shows arrows for `math`, but doesn't show arrows or offer to go to the definition of either `sqr` or `pi`. I think if that can be fixed then Rhombus can be adjusted pretty easily.

```scheme
#lang racket

(define-syntax math (syntax-rules ()))

(require racket/math)

(define-for-syntax tbl (hash 'pi #'pi
			     'sqr #'sqr))

(define-syntax (scope stx)
  (syntax-case stx ()
    [(_ mth id)
     (free-identifier=? #'mth #'math)
     (syntax-property (hash-ref tbl (syntax-e #'id))
                      'disappeared-use
                      (cons
                       (datum->syntax #'here
                                      'math
                                      #'mth
                                      #'mth)
                       (datum->syntax #'here
                                      (syntax-e #'id)
                                      #'id
                                      #'id)))]))
(provide scope math)

```

```scheme
#lang racket/base

(require "a.rkt")

(scope math sqr)

(scope math pi) 

```

---

<div class="post-metadata">

**Author:** ![robby](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/robby/32/7_2.png) [@robby](https://racket.discourse.group/u/robby)\
**Post date:** [December 10, 2023, 1:00am UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/28 "2023-12-10T01:00:46Z")

</div>

This change causes DrRacket to offer a "jump to definition" or "open defining file" but there's still no arrow. I'm actually not sure where an arrow would go!

This passes the test suite and I don't see why this wouldn't be a good idea just in general, so if I can think of a good way to write a test case for it, I'll push it.

```scheme
diff --git a/drracket-tool-text-lib/drracket/private/syncheck/traversals.rkt b/drracket-tool-text-lib/drracket/private/syncheck/traversals.rkt
index 26bbfbda..2c1448f7 100644
--- a/drracket-tool-text-lib/drracket/private/syncheck/traversals.rkt
+++ b/drracket-tool-text-lib/drracket/private/syncheck/traversals.rkt
@@ -968,6 +968,16 @@
   (define req-phase+space-shift (list-ref req-path/pr 4))
   (define require-hash-key (list req-phase-level mods))
   (define require-ht (hash-ref phase-to-requires require-hash-key #f))
+ (when id
+ (define-values (filename submods)
+ (get-require-filename source-req-path user-namespace user-directory))
+ (when filename
+ (add-jump-to-definition
+ var
+ source-id
+ filename
+ submods
+ req-phase+space-shift)))
   (when require-ht
     (define req-binder+modss (hash-ref require-ht req-path #f))
     (when req-binder+modss
@@ -979,16 +989,6 @@
         (define match/prefix
           (id/require-match (syntax->datum var) id require-context))
         (when match/prefix
- (when id
- (define-values (filename submods)
- (get-require-filename source-req-path user-namespace user-directory))
- (when filename
- (add-jump-to-definition
- var
- source-id
- filename
- submods
- req-phase+space-shift)))
           (define prefix-length
             (cond
               [(and (identifier? match/prefix)

```

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [December 10, 2023, 3:20am UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/29 "2023-12-10T03:20:19Z")

</div>

How well does this work for the rhombus programs under discussion (perhaps with the disappeared-use change I posted earlier)?

---

<div class="post-metadata">

**Author:** ![robby](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/robby/32/7_2.png) [@robby](https://racket.discourse.group/u/robby)\
**Post date:** [December 10, 2023, 8:40pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/30 "2023-12-10T20:40:04Z")

</div>

I'm not sure exactly which change you have in mind (I scrolled back and didn't something simple to try, sorry!) but this program:

```scheme
#lang rhombus
math.max(1, 2)

```

does not have a link to `max`, even with the change. Perhaps the disappeared use that you have in mind will fix that, tho?

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [December 10, 2023, 9:04pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/31 "2023-12-10T21:04:00Z")

</div>

It's this commit: [Add disappeared-use for fields. · samth/rhombus-prototype@4c700bd · GitHub](https://github.com/samth/rhombus-prototype/commit/4c700bd47c7fce387fffff792fa85cb93086608f)

---

<div class="post-metadata">

**Author:** ![robby](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/robby/32/7_2.png) [@robby](https://racket.discourse.group/u/robby)\
**Post date:** [December 11, 2023, 12:20am UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/32 "2023-12-11T00:20:10Z")

</div>

Yes, that seems to work, as far as I can tell.

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [December 11, 2023, 2:08pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/33 "2023-12-11T14:08:25Z")

</div>

That sounds like good progress!

What does `identifier-binding` say for each of `math` and `max` -- the binding end of each of those arrows?

When I tried before with [Sam's `scope` example pair of files](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/27) via:

```scheme
#lang racket
(define mp '(file "/home/greg/src/racket/examples/b.rkt"))
(namespace-require mp)
(current-namespace (module->namespace mp))
(identifier-binding #'math)
(identifier-binding #'sqr)

```

I got

- `math`: `#f`
- `sqr`: `'(#<module-path-index:racket/math> sqr #<module-path-index:racket> sqr 0 0 0)`

The problem: I use the "nominal-from" information from the binding end of the arrow, to learn the "proximate" export source.

- For `math`, it's missing.
- For `sqr`, it's wrong^1. The proximate source is "a.rkt", which in turn imports it from `racket` -- i.e. the "a.rkt" step of the chain is elided.

^1: I mean, strictly speaking it's not wrong, because the `scope` macro isn't an import and "a.rkt" where it's defined doesn't export anything. But that's the root difficulty, from my POV: Racket has had a notion of module exports and imports -- and related supporting functions like `identifier-binding` and `module->exports`. If something like `scope` or rhombus doesn't use or extend that, it's going to be opaque to tools.

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [December 11, 2023, 2:29pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/34 "2023-12-11T14:29:30Z")

</div>

It seems to only be partly working for me. When I have

```scheme
#lang rhombus
math.pi

```

I get the usual "Open Defining File" or "Jump to Definition (in other file)" options. The defining file appears to be `rhombus/private/math`. But with `math.max` or `math.max(1,2)` I don't get those options, and instead just the "View documentation for `max` from racket/base" (indicating that it knows the binding but isn't showing anything about the definition).

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [December 11, 2023, 2:44pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/35 "2023-12-11T14:44:05Z")

</div>

Here I think there are two issues.

1. The `scope` macro is somewhat different from how `rhombus` works, because it's `math` itself that's the macro, so things are a little better there.
2. It's not obvious what we want to do with `sqr` in that case -- there isn't a definition of it in `a.rkt` so maybe we want to `racket/math`.

But also I'm a bit confused about what's going on in your example. I think your code is using the `racket` identifiers, which is why `math` is not bound. It's unfortunately not obvious to me how to make that test work for rhombus properly.

---

<div class="post-metadata">

**Author:** ![robby](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/robby/32/7_2.png) [@robby](https://racket.discourse.group/u/robby)\
**Post date:** [December 11, 2023, 4:07pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/36 "2023-12-11T16:07:58Z")

</div>

> [@samth](#):
>
> But with `math.max` or `math.max(1,2)` I don't get those options, and instead just the "View documentation for `max` from racket/base" (indicating that it knows the binding but isn't showing anything about the definition).

I was under the impression that the binding isn't in Racket code in those cases so there's no source to jump to. Am I wrong about that?

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [December 11, 2023, 4:36pm UTC](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511/37 "2023-12-11T16:36:02Z")

</div>

You're right; I just misinterpreted what happened with `pi`.

With that change (PR soon) and your changes to `drracket-tool-text-lib`, this file now supports go-to-definition for all the relevant identifiers in both DrRacket and racket-mode:

```scheme
#lang rhombus/static

math.sum(1,2)

math.atan(1)

Set.length

Set.empty

1 + 2

```

[Previous page](https://racket.discourse.group/t/imports-as-completion-candidates-for-hash-langs/2511.md?page=1)
