mflatt
2018-7-9 12:05:25

Hi Mason - I’m never sure which threads will provoke a response in different channels, but it’s possible that you’l get more of an answer on the mailing list.

For what it’s worth, I haven’t heard performance complaints for plain Racket in the last 5 or so years in the way that I used to, and I think it’s because plain Racket’s performance mostly caught up.

I keep writing “plain Racket”, because performance remains challenge (and I still sometimes hear complaints) for our more ambitious Racket variants, like Typed Racket and its sound interaction with untyped code.

As for the Racket-on-Chez buzz, maybe my message has gotten through: the Racket-on-Chez project will succeed or fail in the near term based on internal merits, like the structure and maintainability of the system. Those are good things, but they’re less exciting than an automatic performance boost.


ryanc
2018-7-9 13:06:50

@leif to clarify, it’s definitely a bug, I was just commenting on what kind of bug it was


samth
2018-7-9 14:05:22

@greg I’m confused about what sense identifier-binding handles plain contract-out ok


greg
2018-7-9 14:09:18

@samth In the sense that, in that case, the nominal-source-id returned by identifier-binding is the original non-contract-wrapped id symbol.


samth
2018-7-9 14:09:38

ah it’s just the right symbol


samth
2018-7-9 14:09:47

not the binding


greg
2018-7-9 14:10:24

Yes, the discussion above was all in the context of “making a go-to-definition tool”.


greg
2018-7-9 14:10:59

For which, if you know the correct file, and know the correct id symbol used in that file, you can find it.


samth
2018-7-9 14:11:59

that seems not true in general to me


samth
2018-7-9 14:12:10

but probably it works for your purposes


greg
2018-7-9 14:13:28

Well yes with this kind of tooling it seems often a thing isn’t true in general, but is true often enough to be useful. :slightly_smiling_face:


samth
2018-7-9 14:15:00

I think the issue is that while rename-out works by design, what you’re doing for contract-out only really works by accident, and so minor variations don’t work


greg
2018-7-9 14:18:31

Empirically the following is useful (but maybe just accidentally): (define (real-name id) ;symbol? -> symbol? (or (object-name (with-handlers ([exn:fail? (λ _ #f)]) (eval (namespace-symbol->identifier id)))) id)) It seems to reliably answer the question, what was the original id symbol <foo> behind provide/contract-id-<foo>.0.


greg
2018-7-9 14:19:23

Reliable enough for me to use that, instead of walking unexpanded file syntax looking for (contract-out [rename _ _ _]) forms — which is what I’d been doing and is obviously a bit slower.


greg
2018-7-9 14:22:31

Anyway, my main sad at the moment is that I have to walk fully-expanded syntax on the target file to discover definition sites, and that full expansion isn’t cached anywhere AFAIK. https://github.com/greghendershott/racket-mode/issues/288#issuecomment-403327777


samth
2018-7-9 14:27:49

@greg couldn’t you cache it yourself?


samth
2018-7-9 14:28:17

either from the previous time you did this, or by changing the eval-handler to do that


greg
2018-7-9 14:31:05

Maybe. What I wrote at that link: > - If expand is (for some files) so slow, can we avoid it? I don’t see how. It’s quite common for definitions to be created by “definer” macros, and these definitions can only be discovered in fully-expanded code. > > - If we can’t avoid it, could we at least shift the cost earlier than <kbd>M-.</kbd>? Could racket-mode generate expansions ahead of time — storing them under compiled/ in (say) .expanded files, or in a new expanded/ subdir? In theory, sure. But: > > - This seems like something that should be done by a raco tool that people explicitly opt in to, much like raco make. (Note there exists a raco expand tool — however its output isn’t syntax with the source location information that we need, it’s plain text syntax-&gt;datum of the expansion.) > > - The file that must be expanded is the “target” of the find-definition — the file identifier-binding says the definition is in. Even if racket-run were to cache the full expansion of the file being run, that’s often not where the definition is. Even if you were to raco some-new-tool all the files in your project, that won’t speed up finding definitions in other projects.


samth
2018-7-9 14:35:34

right


samth
2018-7-9 14:36:26

but racket-mode could still maintain some caches


greg
2018-7-9 14:37:23

Maybe my comment above is “well it wouldn’t be perfect”, which contradicts what I was just saying about “well it’s tooling and the perfect shouldn’t be the enemy of the good”.


samth
2018-7-9 14:37:48

for example, by changing current-eval to call expand, cache that result, and then call the underlying eval


greg
2018-7-9 14:40:02

Yes I could do it for the file currently being run. People are paying for that to be expanded anyway, may as well save that result in case they try to visit something used/defined in that same file. That’s a common case.


samth
2018-7-9 14:41:16

also i think there’s more you can do to get information from zo files


greg
2018-7-9 14:42:54

Oh! I just assumed “bytecode, there’s won’t be any srcloc info”. There might be?


samth
2018-7-9 14:43:05

there’s lots of interesting stuff in bytecode


greg
2018-7-9 14:43:51

That’s a corner of Racket I’ve barely looked at.


samth
2018-7-9 14:44:47

for example, try raco decompile on some file with some definitions, and you’ll see source locations for most functions


greg
2018-7-9 14:45:00

Huh. Wow. OK.


samth
2018-7-9 14:45:25

it’s not obvious to me what part of the structure has those, but it might be the name field of lambdas


greg
2018-7-9 14:45:59

Thanks I’ll dig in and take a look!


greg
2018-7-9 14:46:47

Until now, my only thoughts about zos have been, if they get stale, can I use them as croutons.


ryanc
2018-7-9 14:55:50

@greg re contracts, I think the exported names are bound to applicable substructs of provide/contract-info from racket/contract/private/provide, and that struct stores the original name (identifier). Maybe ask @robby if it’s safe to rely on that?


robby
2018-7-9 14:57:03

Sorry: what’s the behavior you’d like to rely on, @greg ?


robby
2018-7-9 14:58:12

I’m probably okay to guarantee things about names working right, but I should probably add some tests and docs to make sure that that it stays that wya.


ryanc
2018-7-9 15:06:37

@robby the discussion earlier was about how to get from a use of a provide/contract’d name to the original function in racket-mode’s version of Jump to Definition. I was suggesting to @greg that the provide/contract-info struct might be useful. (But now thinking about it again, I’m not sure if it’s useful when looking at expanded code.)


robby
2018-7-9 15:08:31

I don’t think that check syntax relies on that?


robby
2018-7-9 15:09:00

oh, but maybe that’s because it doesn’t work?


ryanc
2018-7-9 15:13:16

I once wrote some code that used it in a module-begin macro to do contract-aware analysis, so I think it works in that context. Just maybe not for a Check Syntax-like tool.


greg
2018-7-9 15:15:39

@robby When the definition is from another file, in DrRacket I usually get the choice, “Open Defining File”. However in racket-mode it tries to find and go to the actual location within the file.


greg
2018-7-9 15:16:44

This means (say) trying to find the source-id or nominal-source-id reported by identifier-binding, in a define-values in fully expanded stx for the file.


greg
2018-7-9 15:17:56

The issue is with (contract-out [rename orig new] ..), identifier-binding doesn’t report orig. It reports new and something like provide/contract-id-orig.0. Neither of which is in the file.


greg
2018-7-9 15:19:23

How to get from provide/contract-id-orig.0 to orig is the question. I used to walk non-expanded file syntax looking for the contract-out / rename form. More recently I noticed that object-name seems to work. Ryan wondered if the struct subtype accessor might provide this.


robby
2018-7-9 15:23:28

(one note: it says “open defining file” when it has not yet expanded the tab that contains the definition (or the file isn’t open), so that’s kind of a red herring here)


robby
2018-7-9 15:26:34

Check Syntax looks at the fully expanded program and tries to find the identifier, but I see that it also doesn’t work.


robby
2018-7-9 15:27:00

Specifically, for this program:


robby
2018-7-9 15:27:04
#lang racket/base
(require "tmp2.rkt")
abc
pqr

robby
2018-7-9 15:27:09

with tmp2.rkt:


robby
2018-7-9 15:27:21
#lang racket

(define abc 1)
(provide
 abc
 (contract-out (rename abc pqr integer?)))

robby
2018-7-9 15:27:32

It goes to the right place for abc but not pqr


robby
2018-7-9 15:29:59

I’m not sure this is check-syntax/emacs-mode’s fault. It may be that contract-out’s expansion needs to change.


mason.protter
2018-7-9 16:05:02

Thanks for the reply and clarification! I’d like to give racket a go someday, I find the philosophy of focusing on DSLs very interesting but as a physicist who needs high performance I’ve never really found a use case for me to delve into racket.


lexi.lambda
2018-7-9 18:15:23

@robby I may be missing something, but isn’t that true even if contract-out doesn’t use rename? I guess maybe the “Jump to Definition (in Other File)” option might work without the rename, but that seems largely accidental, since IIUC Jump to Definition looks at the result of read, not the fully-expanded program? I am obviously less familiar with this than you are, though, so I could be wrong.


leif
2018-7-9 18:17:32

@mflatt Is s-exp->fasl supposed to fail when when current-write-relative-directory is a cons pair? Such as in:


leif
2018-7-9 18:17:36
(current-write-relative-directory (cons (build-path "/" "Users" "leif")
                                        (build-path "/" "Users")))

(fasl-&gt;s-exp (s-exp-&gt;fasl (build-path "/" "Users" "leif" "foo.rkt")))

leif
2018-7-9 18:18:04

Or is that a bug?


robby
2018-7-9 18:38:26

@lexi.lambda it looks at the fully expanddd program


robby
2018-7-9 18:38:36

The define pop down doesn’t


lexi.lambda
2018-7-9 18:39:08

ah! I didn’t realize they were different, but in retrospect, I don’t know why they’d have to be the same.


robby
2018-7-9 18:48:50

It would be better if they were the same, I think.


robby
2018-7-9 18:49:07

and yeah, it seems like the rename-out is not necc. to demonstrate the error.


robby
2018-7-9 18:53:36

just to be clear, I think that what’s happening is that check syntax figures out what file the definition is in, but can’t find the definition, so it just goes to the file (and leaves the insertion point alone).


robby
2018-7-9 18:54:11

but something is fishy, as I think I used this feature (and it worked) the other day.


robby
2018-7-9 18:54:17

maybe there is more to the bug


soegaard2
2018-7-9 19:17:44

The documentation of match says that this pattern should work: (struct struct-id (pat …))


soegaard2
2018-7-9 19:18:27

However I can’t get this to work: http://pasterack.org/pastes/21677


lexi.lambda
2018-7-9 19:19:15

@soegaard2 You just want bird, not struct:bird.


lexi.lambda
2018-7-9 19:19:30

But that won’t work here because you’ve shadowed bird.


soegaard2
2018-7-9 19:19:45

Well, normally. I’d like to know what I can use in the match pattern, when I have shadowed the name.


lexi.lambda
2018-7-9 19:20:15

I don’t think there’s a way to do it if you’ve shadowed the name; match needs the static information bound to that identifier.


soegaard2
2018-7-9 19:20:16

Do I really need to use #:extra-name ?


lexi.lambda
2018-7-9 19:21:45

Can’t you just rename the local variable so it doesn’t shadow the outer name? I’m unsure what you’re asking for.


soegaard2
2018-7-9 19:23:49

That’s the sensible thing to do.


soegaard2
2018-7-9 19:24:22

I was just surprised that I couldn’t use struct:bird which is bound to the struct type descriptor.


lexi.lambda
2018-7-9 19:24:54

struct:bird is bound to the runtime structure type descriptor (that is, a value that satisfies struct-info?).


lexi.lambda
2018-7-9 19:25:08

bird is bound to the structure type transformer binding, which is what match uses.


lexi.lambda
2018-7-9 19:25:13

The difference between them is confusing.


soegaard2
2018-7-9 19:26:30

:extra-name worked


greg
2018-7-9 20:01:42

@samth So reading the zo is easier than I expected, after grokking parse/zo-structs.rkt. I can walk all the mods (including submodules) and find lams and get srcloc. It works, except the srcloc for definitions created by macros is wrong. It’s the location of the macro definition, not the location of the usage of the macro.

Then I noticed mod-binding-names, which is a hashtable of phases to hashtables of symbols to syntaxes. And the srcloc there is correct, even for definer macro usages! And it’s just a simple hashtable lookup! Woot.

BUT. That’s only for the value of mod-binding-names in the file module. For submodules, the value of mod-binding-names is something like #96#. Um…. I’m not even sure what that means — is it something to do with cycle detection??? I don’t see the symbol 'sub in any hash table in the parsed zo when the rkt file has (module m racket (define (sub x) x) (provide sub)). So it doesn’t seem like #96# references something elsewhere?


greg
2018-7-9 20:05:12

greg
2018-7-9 20:05:58

But in the zo-parse output, I have #96=#hash().


greg
2018-7-9 20:06:45

It’s empty. Which fits with me not seeing 'sub anywhere in the zo.



samth
2018-7-9 20:25:03

I think only @mflatt can answer this question


mflatt
2018-7-9 20:26:31

@leif It does look like s-exp-&gt;fasl is broken for that case


mflatt
2018-7-9 20:33:09

@greg Warning before other answers: parse/zo-structs is unusual in that it promises to change with the version. It’s very different for v7, because it’s at the linklet level instead of the module level.


mflatt
2018-7-9 20:37:37

I may be starting to forget, but I think the mod-binding-names field won’t have all defined names. It has a mapping only for names that have to be made up to hide them, such as when the definition is macro-introduced. If (define (sub x) x) appears in the program, then I think there’s no empty for 'sub, but if (define (sub x) x) is macro-introduced so that an unreadable name sub.1 is made up, then 'sub.1 will make to 'sub in the table. Is that consistent with what you’re seeing?


greg
2018-7-9 20:39:50

Well I’m on 6.10 at the moment (matches something I have deployed, waiting to upgrade). With the zo for this file: https://github.com/greghendershott/racket-mode/blob/various-changes/test/defn-examples.rkt


greg
2018-7-9 20:40:34

I’m seeing mod-binding-names entries for all the file module bindings, including things like plain.


greg
2018-7-9 20:41:39

I’m seeing #96# => #96=#hash() as the mod-binding-names for all the submodules in the file, like sub or red-herring.


greg
2018-7-9 20:43:06

I don’t have an example of a macro-introduced definition in a submodule. I’ll try adding one to see if that “forces” a non-empty hashtable for the submodule.


greg
2018-7-9 20:46:25

It doesn’t.


greg
2018-7-9 20:47:31

Welp, maybe this behavior means I should shelve this idea.


greg
2018-7-9 20:47:55

I did notice the warning about version changes, but was willing to maybe try to track along with those if the result was worthwhile.


greg
2018-7-9 20:48:39

I can at least do some more work on caching fully-expanded code.


greg
2018-7-9 20:49:03

Maybe for RacketCon day 2 we could have a little session about tooling stuff.


mflatt
2018-7-9 20:49:20

Apparently I misremember, so I’ll look a little more


greg
2018-7-9 20:50:55

Thanks but don’t spend too much time. The immediate motivation is to make go-to-definition on some sources files be “instant” instead of take a few seconds because fully-expanding them is slow.


greg
2018-7-9 20:51:34

I love “instant” as much as the next person but there’s a cost:benefit to everything.


mflatt
2018-7-9 20:55:11

Adding a macro-introduced definitition does seem to trigger the table When I change the sub submodule to (module sub racket/base (define (sub x) x) (define-syntax-rule (q) (define other 8)) (q) (provide sub (rename-out [sub sub/renamed]))) then the table for sub has sub and q. So, I think it’s that when there’s any identifier like a macro-introduced one, then the table is generated. Otherwise, it can be synthesized from the module content easily enough.


greg
2018-7-9 21:01:04

@mflatt Is that on 6.12, or 6.90-ish, or other?


mflatt
2018-7-9 21:01:14

6.12


greg
2018-7-9 21:01:37

OK I’ll try with that, too.


mflatt
2018-7-9 21:59:18

@leif I have a repair to push for s-exp-&gt;fasl


mflatt
2018-7-9 21:59:55

(after running more tests)


leif
2018-7-9 22:36:54

@mflatt Cool, thanks.


leif
2018-7-9 22:37:28

BTW, is there any way to get the location of your current file (if its on your filesystem) at syntax time?


leif
2018-7-9 22:37:44

Like: (begin-for-syntax (writeln (quote-module-path)))

Will just return ’<modname>


leif
2018-7-9 22:38:20

Anyway, without that it seems like its not possible to do something like, say, dynamic-require at phase > 0


mflatt
2018-7-9 22:40:58

I think you want (variable-reference-&gt;module-path-index (#%variable-reference)), but I don’t know if there’s a prettier wrapper along the lines of quote-module-path.


leif
2018-7-9 22:42:23

I actually tried that first.


leif
2018-7-9 22:42:51

But if, say the file is in: /Users/leif/bizzle.rkt, then:

(begin-for-syntax
  (writeln (variable-reference-&gt;module-path-index (#%variable-reference))))

leif
2018-7-9 22:43:00

gives #&lt;module-path-index='bizzle[7427]&gt;


gfb
2018-7-9 23:43:02

Maybe I’m missing something, but how about just: (begin-for-syntax (writeln (syntax-source #'here)))