Closed ghost closed 4 years ago
It is a goal for racket-mode to support #lang
mechanisms described
in Creating Languages.
Is htdp/bsl
's check-expect
using one of those to work with
DrRacket, or something else/special? I think the latter, but I'm not
sure. I don't think I'll be able to take a look at this soon; maybe
someone else who sees this, could?
Full disclosure: The HTDP langs have not been a high priority for racket-mode. They are wonderful in an education setting -- where I've assumed most people would use DrRacket.
The equivalent #lang racket
program using check-equal?
from
rackunit
does work:
#lang racket
(require 2htdp/image
rackunit)
(define (double n) 0)
(check-equal? (double 3) 6)
(check-equal? (double 4.2) 8.4)
When that program is racket-run
, the racket-repl-mode
buffer shows:
--------------------
; FAILURE
; /tmp/issue-316.rkt:6:0
name: check-equal?
location: issue-316.rkt:6:0
actual: 0
expected: 6
--------------------
--------------------
; FAILURE
; /tmp/issue-316.rkt:7:0
name: check-equal?
location: issue-316.rkt:7:0
actual: 0
expected: 8.4
--------------------
issue-316.rkt>
The teaching language testing framework needs a call to the test
function at the end of the file, which is automatically inserted by the language and/or by DrRacket (I forget the mechanism).
@samth : It must be DrRacket that does it, because it certainly doesn't happen in Racket Mode.
(test)
doesn't seem to be defined, and I can't find anything in the docs to indicate what it would be. It would be nice to know what it is as I prefer using Racket Mode over DrRacket (working Vim bindings!)
It's just running the test
submodule (which is generated by the language).
An easy workaround is adding
(require test-engine/racket-tests)
(test)
at the end of your file.
This worked, thank you :)
I'm not sure how I overlooked @samth 's comment from June 17, 2019. Sorry!
Now that I understand it's simply a (hidden!) test
submodule, another simple work-around in Racket Mode is to use the M-x racket-test
command (bound by default to C-c C-t).
If I understand correctly, this is similar to #430, where a #lang
created a (hidden!) main
submodule. In this case, instead it's a hidden test
submodule.
I handled #430 with commit 5226366: Now M-x racket-run
bound to F5 runs a main
submodule if any, else the file module. (The previous, explicit behavior is still available as M-x racket-run-module-at-point
C-c C-c.)
Possibly I should extend the new racket-run
F5 also to run hidden test
submodules, to even more closely emulate the DrRacket Run button behavior?
@cflewis The reason I keep typing "hidden!" is because the "normal" #lang racket
way, you'd put main
, test
, or other submodules in your code, explicitly. And so the "traditional" M-x racket-run-module-at-point
is kind of handy. Whatever module point (the cursor) is in, will be run. It's not wrong for some of these #lang
s to create the submodules for you, it just wasn't something I was accustomed to seeing, and until #430 Racket Mode didn't even attempt to handle those.
One thing just to note here is the notion of "hidden" is really racket-mode-specific, since module+
is "hidden" in the sense that it also expands to a submodule, but racket-mode recognizes it specifically (and somewhat heuristically).
@greghendershott : I would not wish to be so presumptuous as to have a beginner using a kinda-but-not-really supported dialect of Racket inform how a full-fat Racket plugin should operate!
I think the thing that makes this really an issue is that the "failure" is silent. (check-expect)
simply does nothing, which is pretty confusing. One would at least think that if (check-expect)
wasn't going to do what HTDP says it would do, that it was not doing it because (check-expect)
wasn't a known definition, and throw an error that way. Unfortunately, it is a known definition, but it just doesn't do anything without the invisible cajoling.
As you said, this is an easy workaround: I just rebind my racket-run-and-switch-to-repl
shortcut to do run tests as well.
For me, I think it would be totally fine for this to be a Google-able GitHub issue for people running into trouble. Perhaps there could also be a racket-test-and-switch-to-repl
command to shorten the distance.
@samth By "hidden" all I meant is "the language adds a submodule that is not apparent in the user's program source". run-module-at-point
doesn't work very well when there is no module within which to put point. :smile:
@cflewis I agree 100% about the UX. Handling the beginner-student languages, at all (much less making a just-works out-of-box experience) just hasn't been a high-priority goal, so far. I don't dogfood them. I'm not even sure, out of the relatively few people who use Racket Mode, how fewer many people use them.
Having said that, I think I could extend the F5 racket-run
to handle test
as well as main
submodules -- regardless of who/what creates them. :wink: That's my new plan for how to handle this issue. Thanks again for commenting here, to revive this!
FWIW, I used racket mode for teaching languages when I was an AI for a class that uses HTDP as the textbook. I think I used the workaround Sam mentions above to get check-expects running.
Sorry to be a Necromancer, I just want to say that I literally googled check-expect racket-mode
and this open issue saved me from a lot of trouble and further confusion.
I agree that the problem is the function failing silently.
I'm using racket-mode since day one I think, DrRacket is a good software but it's very memory hungry and slow on my laptop, also even common shortcuts like C-backspace doesn't work on it, racket-mode provide a lot of QoL for students as well. :)
If you later decide to implement a fix, would not be better to include the hidden (test)
on (kbd "C-c C-t")
instead of on (kbd "F5")
?
I'm assuming that loading the (test)
module might slow down a bit (even if unnoticeable), someone running (kbd "C-c C-t")
is explicitly asking for running tests, and that might as well include loading the hidden (test)
, so the person is already expecting that racket-mode would do some "extra-work".
This would avoid racket-mode to reproduce the behavior of DrRacket of calling it's various hidden functions when you're doing a "standard run".
Sorry if it sounds a bad suggestion, I'm just thinking that as those "hidden features" of DrRacket caused confusion, might be better to avoid implement then in the same way or at least document it better for users to know that hidden modules are being called.
I had the "engine hood open" working on #492, looking at code in the same neighborhood in the implementations of both Dr Racket and Racket Mode, and decided also to tackle the bigger change of implementing this.
The documentation for the new customization variable racket-submodules-to-run
describes the run commands for which this works (or not).
racket-submodules-to-run
Extra submodules to run.
This is a list of submodules. Each submodule is described as a list, to support submodules nested to any depth.
This is used by commands that emulate the DrRacket Run command:
racket-run
racket-run-and-switch-to-repl
F5It is NOT used by commands that run one specific module, such as:
racket-run-module-at-point
C-c C-k or C-c C-cracket-test
C-F5 or C-c C-tracket-profile
The default value is '((test) (main))
, similar to Dr Racket.
I should point out that, in addition to racket-submodules-to-run
having a global default value, you can override it easily per-file. Just use the general Emacs ability to specify file-local variables.
For example:
#lang racket
(module+ test
"I am the test submodule")
(module+ main
"I am the main submodule")
"I am the file module"
Press F5 for racket-run-and-switch-to-repl
and you see:
"I am the file module"
"I am the test submodule"
"I am the main submodule"
Back in the file buffer, do M-x and enter add-file-local-variable
.
Enter racket-submodules-to-run
.
Enter the value ((test))
. Note: Do not add the leading quote '
.
Now the edit buffer shows:
#lang racket
(module+ test
"I am the test submodule")
(module+ main
"I am the main submodule")
"I am the file module"
;; Local Variables:
;; racket-submodules-to-run: ((test))
;; End:
This will take effect every time you visit the file. But you haven't done so, yet, since making this change. So do e.g. M-x revert-buffer
. (Emacs suggested doing this, but you might have missed the message in the echo area.)
Now when you F5 it outputs:
"I am the file module"
"I am the test submodule"
In other words it did not run main
anymore, just test
as you specified.
Dr. Racket produces an eval result telling me the expected result does not match my
(check-expect)
s. Racket-mode produces any empty result.