shu--hung
2021-3-15 07:00:34

Because it expands to code that increment the count when the module is being instantiated at phase 1, rather than incrementing the count at the time a module is compiled


shu--hung
2021-3-15 07:01:34

On the contrary, I’m not sure if that can work in internal definition contexts.


shu--hung
2021-3-15 07:02:30

(^ due to the use of begin-for-synta)


shu--hung
2021-3-15 07:11:45

btw the example in You Want it When is like this. Same for the type system implementation in Languages as Libraries.

I guess the modern implementation of struct is fancier, though.


sorawee
2021-3-15 07:18:01

Conveniently, I only need it to work at the module level, since module+ can’t appear in an internal definition context anyway.


sorawee
2021-3-15 07:18:11

So this is perfect. Thanks again :slightly_smiling_face:


sorawee
2021-3-15 07:18:23

Yeah, I need to reread those papers.


sarna.dev
2021-3-15 08:25:37

haha, I’ve found a solution - https://docs.racket-lang.org/natural-cli/index.html\|https://docs.racket-lang.org/natural-cli/index.html :) it wraps cmdline in a very nice way


sschwarzer
2021-3-15 11:35:01

I have a question (or several) about startup time. When I run #lang racket/base "Hello world" with $ time racket hello.rkt , I get about 145 ms runtime. Translation with raco make results in a runtime of 125 ms. raco exe with $ time ./hello gives about 130 ms.

With #lang racket, the runtimes are 380 ms, 290 ms and 335 ms, respectively.

(For comparison: On the same computer, Nim, Go and OCaml take about 5 ms for a “hello world” program, compiled Chicken Scheme takes 10 ms, Python takes 55 ms.)

My understanding/assumption is that raco make and raco exe processing does all the macro expansion and most of the code is compiled to machine code (with Racket 8.0). Why does the program still take that long? What does Racket spend the time on? Probably related: Why are the startup/runtimes with #lang racket so much longer than with #lang racket/base, even if I don’t use the additional functionality of #lang racket over #lang racket/base?


alexharsanyi
2021-3-15 12:32:17

You can shave a bit more time if you use #lang racket/kernel , but if you are serious about the speed of your hello world program, you need to use assembly: https://jameshfisher.com/2018/03/10/linux-assembly-hello-world/


sschwarzer
2021-3-15 13:02:04

No, I’m not that serious about the runtime. :smile:


sschwarzer
2021-3-15 13:11:46

More seriously though, I dislike “having” to think about using a feature because of how the additional require will increase the runtime. This is rather pronounced if you use #lang racket/base , but require racket/match.

So my goal isn’t to reduce the runtime at all costs, but to reduce the runtime without reducing the used language/library features a lot.

What I’d wish for would be a “minimal” startup time of ≤ 50 ms. Ideally, a mere require shouldn’t increase the runtime at all (unless the module has to do some expensive initialization).

Anyway, although I keep telling me that the current Racket runtimes should be fine, I come back to the question why Racket is relatively slow (despite that execution times, apart from the startup, are usually pretty good).


laurent.orseau
2021-3-15 13:17:53

Nice!


samth
2021-3-15 13:37:54

Yes, in general side effects in macros are usually better as side effects in begin-for-syntax in the expansion of macros


samth
2021-3-15 13:42:38

On the pattern matching duplication question, I think there’s 1. match 2. a collection of sexp/syntax matchers (syntax-case, syntax-parse, datum-case, one in the expander) 3. redex


samth
2021-3-15 13:44:24

They use pretty different implementation strategies and have fairly different constraints, but also it’s a lot of different ones so it seems like something could be unified


sorawee
2021-3-15 14:39:40

I get an error unrecognized parsed form: (parsed-define-syntaxes ...) at the REPL, definitely due to how top-level being hopeless. Is this considered a bug (it looks like an internal error to me) and should I report the issue?


philip.mcgrath
2021-3-15 14:46:48

That’s all fine. The only reason not to bind static information to a name is if you want to use it with something like match, struct-out, or shared. Specifically, the only effect of #:omit-define-syntaxes is to not create a structure type transformer binding: https://docs.racket-lang.org/reference/structinfo.html


samth
2021-3-15 14:47:48

yeah that doesn’t seem like an error your should see


philip.mcgrath
2021-3-15 14:48:37

(Though I wonder if you might want to call the struct group-param for a single param.)


sorawee
2021-3-15 15:06:39

Unfortunately, this results in 2. Ideally I want it to be 1.

#lang racket (module defn racket (provide mac get-mac) (define-for-syntax counter 0) (define-for-syntax (inc!) (set! counter (add1 counter))) (define-syntax (mac stx) #'(begin-for-syntax (inc!))) (define-syntax (get-mac stx) #`'#,counter)) (module foo racket (require (submod ".." defn)) (mac)) (require 'defn 'foo) (mac) (get-mac)


sorawee
2021-3-15 15:07:23

That is, I only want “leaking” to occur for module+, but not across modules in general.


sschwarzer
2021-3-15 15:27:46

@philip.mcgrath I don’t understand everything under that link, but I think I have a better idea now what’s going on. :slightly_smiling_face:

Regarding the name group-params, it means multiple params (represented by the fields) for a single group. On the other hand, it may be an option to name the hash groups-params because the hash contains params for several groups.

Besides, now I wonder if it’s more common in Racket code to use singular or plural for the names of hashes (singular as in: “if you use the hash and hash-ref, you get a single value back” or plural as in: “this hash contains multiple values”).


sschwarzer
2021-3-15 15:39:27

For the record, if I use #lang racket/base and require racket/match, the runtimes (uncompiled, raco make, raco exe) are 290, 230 and 270 ms, respectively. This is about twice the time as for the program without (require racket/match) .


samth
2021-3-15 15:59:01

There are a variety of things that contribute to startup time. The Racket binary takes about 55 ms to start up. Then loading the expander takes some time, even though that’s just creating some top-level values. Then loading racket/base involves substantial IO, plus executing the top-level of a bunch of files, even though that mostly just creates functions, and some of it happens at multiple phases (about 120 linklets get instantiated to start racket/base). Then loading more modules just takes more time. Also, the serialized form of compiled code has to be read in and turned into values, which is fast but not instant in all of these processes.


samth
2021-3-15 16:00:51

Why do you want this semantics?


samth
2021-3-15 16:01:22

module+ is just a macro, so I don’t know exactly what semantics you do want.


samth
2021-3-15 16:03:25

You might find the output you get if you try: PLT_LINKLET_TIMES=1 racket -l racket interesting.


soegaard2
2021-3-15 16:08:14

@sschwarzer If I recall correctly, much of the startup time is due to i/o. I remember @mflatt at some point thought about packaging the needed files into a single file (zipped?), thereby reducing the number of files to access. I don’t know, if this idea was implemented.


sschwarzer
2021-3-15 16:16:56

@samth Yes, that’s very interesting, thank you. Also the different statistics for racket/base vs. racket.


samth
2021-3-15 16:17:41

significantly faster startup would require probably some combination of: - being able to mmap in serialized compiled code - being able to determine that modules are pure statically so that less execution has to happen at startup - creating tools that flatten programs into single files that can then be compiled into the binary


sschwarzer
2021-3-15 16:18:08

I had thought/hoped that raco exe would do that.


sschwarzer
2021-3-15 16:19:00

@samth What does “faslin” mean?


samth
2021-3-15 16:20:33

that’s deserializing from the “fasl” formalt


sorawee
2021-3-15 16:38:42

Well, I want to simulate a scope of a variable in a module context. So:

#lang racket (module foo racket (define-syntax x ...) (module+ test ;; x is in scope here )) (require 'foo) ;; but not here, since it's not provided


samth
2021-3-15 16:39:47

Maybe you want syntax parameters?


sorawee
2021-3-15 16:45:50

Not sure how syntax parameters will help. What I’m providing are simply mac and get-mac (in the above example — or define-mixfix and #%app for the mixfix library). It doesn’t look like I have anything to syntax-parameterize over in the first place, let alone the meaning of the syntax parameters, etc.


samth
2021-3-15 16:47:43

Ah, ok. In that case I think define-mixfix should bind an identifier, and maintain a hash table mapping that identifier to whatever, and then #%app should look it up. Just like types work.


samth
2021-3-15 16:47:50

And then scope is just scope.


greg
2021-3-15 17:09:32

@robby Not urgent, but when you have a chance, this intersects two of your areas, contracts and drracket. 1. Given some function foo, contract-out defines a wrapper function named provide/contract-id-foo.1, and, exports that renamed as “foo”. As a result, provide/contract-id-foo.1 is the source identifier reported by identifier-binding (and therefore syncheck:add-jump-to-definition). 2. Currently check-syntax does not call syncheck:add-definition-target for that wrapper definition provide/contract-id-foo.1. What if it did — pointing to the location of (say) foo in the contract-out form. Does that seem correct to you, to start doing that?


greg
2021-3-15 17:09:58

If so I think I’d like to make a PR to add that. It would simplify jumping to definitions.


greg
2021-3-15 17:11:28

(To-date, Racket Mode has tried to be clever about jumping directly to foo, transitively, “through” the contract wrapper. But I’ve been working on similar for a “database” representation, and I’m realizing it’s better to be “honest” about the reality that there are two separate definitions, and store them as such. Any transitive jumping should be a higher-level thing if desired.)


greg
2021-3-15 17:17:58

Context: I’m sharing more for the comments but the small amount of code might be useful too idk: https://gist.github.com/greghendershott/eccdb9b847430889e7f992842e13a849#file-pdb-rkt-L117-L239


robby
2021-3-15 17:24:58

re the parenthetical: that’s the decision that check syntax has been taking. I think that’s useful in the contract case as you “pass by” the actual definition of the contract and having a look might well be what the programmer wanted to do.


greg
2021-3-15 17:26:07

There is a raco demod but (a) I think it might not work in Racket CS and (b) I think it’s motivation was more about whole-program optimization opportunities than reducing I/O for load times?


greg
2021-3-15 17:26:39

All the "I think"s in that sentence mean that I don’t really know what I’m talking about, but someone else might. :slightly_smiling_face:


robby
2021-3-15 17:26:42

I don’t know if I’m fully understanding your proposed change but doing something that somehow takes into account the names that the contract system uses in contract-out doesn’t seem right.


robby
2021-3-15 17:27:08

If we really felt we needed to know something about the macro we should define a protocol and the change the contract system to follow it.


robby
2021-3-15 17:27:18

(eg some property or something that the macro could put into the expanded thing)


robby
2021-3-15 17:27:57

There are probably other things that would also benefit from following the protocol and we could document it, etc.


greg
2021-3-15 17:29:15

Also “it’s” => “its”.


sorawee
2021-3-15 19:15:06

Not sure if I understand your comment. define-mixfix(-rule) doesn’t create any binding for users to use. It simply records the syntax transformer. It’s #%app’s job to walk through all syntax transformers to perform a transformation. Here’s an example of its usage:

(define-mixfix-rule (a #:+ b) (+ a b)) (#%app 1 #:+ 2) ; expands to (+ 1 2) It’s true that internally, define-mixfix-rule creates a binding and record this binding in a data structure. The crux of the issue, then, is that when #%app walks over the data structure to find a syntax transformer to use, it will see leaked bindings from other required modules, assuming that define-mixfix-rule compiles to begin-for-syntax. But if define-mixfix-rule doesn’t compile to begin-for-syntax, #%app in module+ won’t see the data structure.


samth
2021-3-15 19:16:31

I think my answer is that you want the connection between define-mixfix-rule and #%app to go via a binding, so instead of just walking the hash table, you look up that binding.


sorawee
2021-3-15 19:20:26

I see what you mean now. Unfortunately, the whole point of mixfix is that there’s no single binding that is responsible for carrying the information, unlike regular macros. So while your suggestion would certainly work, it will defeat the whole purpose of the library.


sarna.dev
2021-3-15 19:21:17

Racket and OCaml seem to be awfully similar - they’re both mostly functional, they both have (underused) object systems, delimited continuations, good ways to extend the language (macros and extension points). TIL Racket even has a module system, just like OCaml.

what unique advantages does Racket have? from the “making stuff in it” perspective, not from the educational/research/creating new languages perspective (as you can’t really compete with Racket in these fields)


samth
2021-3-15 19:21:42

Why not put a binding on \|#:+\| or something like that?


samth
2021-3-15 19:22:11

In general, I think you either need to do what I’m suggesting, or take over #%module-begin to implement module scoping yourself.


samth
2021-3-15 19:25:30

Some unique aspects of the language, relative to OCaml: - concurrency control with threads and events - in-process control of resources, with eventspaces and custodians - delimited continuations (I think the Racket support is in a different category than the OCaml support) - dynamic evaluation (with eval and friends) - an extensive and high-quality standard library, including lots and lots of cross-platform graphics support


sarna.dev
2021-3-15 19:27:13

thanks @samth! I guess Racket’s eval is different than others? I’ve been always told to avoid eval like the plague :)


samth
2021-3-15 19:27:57

No, you should definitely avoid eval. But there are some situations where eval is needed; for example DrRacket calls eval on your code.


sarna.dev
2021-3-15 19:28:22

oh I see. and with sandboxes stuff is a lot safer, isn’t it?


samth
2021-3-15 19:28:50

yes, that’s what I mean — lots of languages have eval but Racket has high-quality support for it.


sarna.dev
2021-3-15 19:29:40

got it! thanks for explaining, I really appreciate it :)


greg
2021-3-15 19:49:38

What check-syntax reports (via identifier-binding) is the identifier that contract-out made up, e.g. provide/contract-id-foo.1. So I think that horse has already escaped the barn?


greg
2021-3-15 19:49:44

I think the challenge is 1. how to find the horse (provide/contract-id-foo.1 is nowhere in the expanded code! — provide/contract-id-foo is) and then 2. how to make that horse lead us to foo. :)


greg
2021-3-15 19:51:00

I like the idea of an official protocol.


greg
2021-3-15 19:51:37

For 2 it seems easy enough to have some syntax-property saying “I am the wrapper for foo”?


greg
2021-3-15 19:52:38

I’m not sure what to do about 1 (the extra ".1" suffix ) because I don’t understand the mechanism or rationale for that. If you have some idea that would be great!


greg
2021-3-15 19:53:56

It’s just very weird now because normally when identifier-binding reports that an identifier is defined somewhere, sure enough it is there in the expanded syntax among the define-values or define-syntaxes forms (in my limited experience).


laurent.orseau
2021-3-15 19:54:12

I seem to remember that OCaml gui was based on tk 15 years ago. It has likely evolved since then, but that wasn’t a great experience at the time. OCaml is a very nice language overall though.


greg
2021-3-15 19:55:23

(In the past I’ve tried to work around this by trying to find things using the nominal-id reported by identifier-binding, or even trying to walk non-expanded code looking for contract forms. But I was hoping to cast away all such hacks and heuristics forever.)


greg
2021-3-15 19:56:39

In that gist I simply have a more focused and barely more principled hack. :slightly_smiling_face: So it’s progress but a real protocol is definitely best.


greg
2021-3-15 19:58:54

TL;DR that gist has both (a) a hack that should be changed into an official PR/change for racket/contract and (b) a non-hack that I think would be a good for PR for drracket/check-syntax, which is to call syncheck:add-definition-target the definitions of contract-out wrappers discovered via (a). I think that’s a better summary of what I’m proposing.


greg
2021-3-15 20:00:19

Maybe I should open a PR for drracket/check-syntax? The discussion there will probably lead to you suggesting I move the hacky parts into a PR for racket/contract in the form of a real protocol. That might be easier than me Slack-ing too verbosely?


samth
2021-3-15 20:03:53

I think OCaml does not come with a standard GUI library the way Racket does.


laurent.orseau
2021-3-15 20:07:30

Too bad. It’s certainly a lot of work though, and I’m very grateful that racket has one!


sarna.dev
2021-3-15 20:21:57

most people seem to be using this for native GUI in OCaml https://garrigue.github.io/lablgtk/\|https://garrigue.github.io/lablgtk/


sarna.dev
2021-3-15 20:23:52

and a lot of people use standard library extensions/replacements, there are at least three popular ones (Batteries, Jane Street’s Core, Containers)