
Can you give the corresponding default output for comparison? :slightly_smiling_face:

In any case that looks very readable indeed.

good idea

here’s what it looks like if you use structs:

and this monstrosity is what you get if you use lists:

if you also replace the enum types with quoted symbols (that is, if you go from using (define-enum-type twixt-player (red black))
to just using 'red
and 'black
symbols) you get this:

pop quiz: in the struct and list versions, do positions print the column first or the row first?

In Pyret, the error would be further refined to show that “up-left-link” is expected to be “down-right-link”. But it will also show the context (the current output) for the sake of completeness

Yes, that kind of thing is super helpful too. Rackunit would need to be extended in order to support that though.

Not sure if this is really just a Rackunit issue. It looks like the container data structures need something that is stronger than gen:equal+hash
that will be able to localize mismatch, right?

@notjack thanks! So it’s not just syntactic formatting, you’re also using keyword arguments instead of positional arguments IIUC. Which probably means this pretty-printing can’t be straightforwardly used as a replacement of the default one, since structs need to be augmented with keyword information I guess?

@sorawee A super generic way of expressing this is probably not desirable. The general problem is that “this thing was not equal to that thing” is not always a good error message. Consider a test that checks if a webpage contains some string: it would be really useful if the test failure could point it out when the webpage contained a string that was almost correct, save for a typo. Domain-specific assertions are a very valuable feature.

@laurent.orseau It’s more than that. Doing this for all structs wouldn’t be great, because some structs have an obvious field order and some don’t. Nobody wants to write or read (point #:x 5 #:y 8)
- it’s redundant. Rebellion tries to address this by letting you choose between (define-record-type point (x y))
(unordered, keyword arguments, prints field names) and (define-tuple-type point (x y))
(ordered, positional arguments, doesn’t print field names).

You could also not change structs and just provide a constructor that takes both positional and keyword arguments? Also, positional works well only for a very small number of values, and personally I wouldn’t mind reading (point #:x 5 #:y 8)
which I find very clear, in particular for a reader who didn’t write the struct definition :slightly_smiling_face:

Allowing the same type to accept both forms would make contracts and docs harder to write for not much benefit. Plus, I find that being able to express whether a type is positional or not makes it much easier to read a series of type definitions. Similar to how it’s easier to understand what a group of functions does when they specify whether they return lists or sets. It communicates intent to the reader.

It can be used badly: you shouldn’t throw a dozen fields into a tuple type in a random order. So what I recommend is defaulting to record types, then using tuple types when you have a good reason to. Just like macros can be used badly, but you can avoid that by using functions by default and resorting to macros only when you understand why you need them.

Makes sense

Does someone have an example readily available (or one in the docs I haven’t come across) where I’m providing a scheme function as a callback to a C FFI along with a scheme struct as a void* userdata
that will be provided to the callback, and that I can cast back to the scheme struct to get info from?

It’s hard for me to say without really understanding all the moving parts. It sounds like thread groups could help, if you need/want to influence the scheduler. (I’ve not needed to do that, so far, so I don’t have any hands-on experience.)

I’m interested in contributing back some things to drracket/check-syntax
. Just not yet sure what, or when.

For example the biggest addition I needed was for completion candidates: What are all the imported bindings (net of stuff like {only except prefix rename}-in
. And also, what are all the module and lexical bindings, whether used or not. Currently I return one set of symbols. I’m not tying to be precise about “well these bindings are available when the user is typing inside this submodule”, and certainly not “when the user is in this lexical scope”. But someday, maybe, I’d want to be that precise? And it shouldn’t be a flat set of symbols — instead it should be some tree with module and lexical scoping?

So maybe this should make contact with some Racket Mode users in the real world, and evolve or mature a bit, before getting baked into drracket/check-syntax
.

The website still says Racket is under the LGPL.

Also I always have a dilemma, because I try to support older versions of Racket (e.g. someone is using debian stable or whatever). So, any code I have to do more than what drracket/check-syntax
provides, today, I’ll still need as a fallback for awhile. Plus if I don’t use my fallback with a newer Racket, then it’s more testing permutations, blah blah blah.

And to complicate things more, I ship as an Emacs MELPA package. It’s not a Racket package. So it’s not some simple thing like specifying a required version of drracket/check-syntax
in deps
in info.rkt
.

All of the above is not excuses, I’m just explaining there is a bit of a speed bump, with more “ceremony” if I go over it. That doesn’t mean I never will go over the bump, I just think hard, beforehand. :slightly_smiling_face:

OTOH there are things where it’s impractical for me to provide a fallback or fix, like https://github.com/racket/drracket/issues/110 — where I’d be glad to contribute a fix if I can ASAP, and also, tell users “well for that you just need a newer drracket/check-syntax
, sorry”.

Can you file a bug?

I think I’m the most recent person to touch DrRacket’s completion support, and I generally think extending it to be more like racket-mode would be a big improvement.

I agree. I think I need things to gel for awhile. I’m still too much at the stage of being happy that completion candidates work, at all, without running the program. Therefore if completion candidates include all imports for all submodules? Fine with me. But I can already see the bug report: “It offers get-pure-port
is a completion candidate but this submodule doesn’t require net/url
, some other module does. Shouldn’t it pay attention to what (sub)module form point is within?” And they’d have a point. Today I don’t feel like it’s a very important point. :slightly_smiling_face: But it’s early days.

I think it is great you are thinking hard about these things!

The current DrRacket behavior is to only give completions for documented required bindings, so any variation on your current implementation is likely an improvement

Also, the one thing I thought was missing from your blog post was installation instructions

does 2htdp use opengl as a backend?

No. The racket draw library uses Cairo.

Can anyone using Linux or Windows confirming this issue? https://stackoverflow.com/questions/60255002/

Note that I use Mac and it works fine.