Is typed racket compilation slow when using prefab structs?

I was trying to write an AST using something like this:

(define-type Exp (U Const Op ...))
(struct Const (...) #:prefab)

without prefab it is ok, but when I added prefab it takes more than a minute from clicking Run to getting a cursor in the interactions window. I tried typed/racket/optional but it is the same.

Does this look like a bug or is it normal because of the stuff that prefab adds?

1 Like

Can you give the code that is slow so I can test it out?

Sure, just this file after adding the prefabs and clicking run on the editor goes from 2 secs to minutes.

#lang typed/racket

(provide J-Exp J-Num J-Boolean J-Var J-Plus J-Eq J-Not J-Read
         J-Com J-If J-While J-Assign J-Output J-Seq)

(define-type J-Exp (U J-Num J-Boolean J-Plus J-Read J-Eq J-Not J-Var))
(struct J-Num ([value : Integer]) #:prefab)
(struct J-Boolean ([value : Boolean]) #:prefab)
(struct J-Var ([value : Symbol]) #:prefab)
(struct J-Plus ([left : J-Exp] [right : J-Exp]) #:prefab)
(struct J-Eq ([left : J-Exp] [right : J-Exp]) #:prefab)
(struct J-Not ([value : J-Exp]) #:prefab)
(struct J-Read () #:prefab)

(define-type J-Com (U J-If J-While J-Assign J-Output J-Seq))
(struct J-If ([cond : J-Exp] [then : J-Com] [else : J-Com]) #:prefab)
(struct J-While ([cond : J-Exp] [action : J-Com]) #:prefab)
(struct J-Assign ([var : Symbol] [value : J-Exp]) #:prefab)
(struct J-Output ([value : J-Exp]) #:prefab)
(struct J-Seq ([left : J-Com] [right : J-Com]) #:prefab)

What is slow is the compilation itself, not the execution. I was not very clear on the post.

Runs out of memory for me before it finishes compiling in DrRacket. Ouch.

Thanks. It looks like the compilation time is dominated by generating contracts for the functions you're providing. If you provide fewer structs compilation is much faster. (Obviously that's not good, but it might be a useful workaround for you.)

yeah, what I'm doing is removing the "#:prefab"s, so it compiles fast again, and I'll write a separate printer function when I need it. It was cool to have an auto-magical serializer, but it's not a problem.

Perhaps serializable-struct works in Typed Racket?

I think not. It doesn't have a typed module and it doesn't support the normal (for typed racket) field typing syntax.

What's special about #:prefab here?

At first I guessed you mean contracts for all the struct accessor functions -- in which case #:transparent would also be a problem.

But #:transparent expands quickly. And either way there is no struct-out involved so I'm wondering contracts for what purpose?

(Obviously I should just look at the fully expanded code, but.... :smile:)

1 Like

The problem is that contracts for prefabs have to check the field types, rather than just relying on the predicates. Since anyone can construct an instance of those prefab types, the contracts have to walk the entire value to check that it matches the type.

I think what's going on is that Typed Racket effectively inlines the entire types into each contract so the generated code (and the runtime to generate that code) is very large. Typed Racket could definitely do better here, but the relevant code is pretty tricky.