
Thanks Greg. This doesn’t really apply to my case though: • It’s not a http server thing. I do have connections to clients programs, but a constant and small number of them (~10) and they never exit. • The clients only read/write to file with file->value
and write-to-file
, plus a surrounding with-output-to-file
. I’d be rather surprised if any of these were not closing the input/output port automatically via a dynamic-wind
equivalent, once an exception is raised (from with-limits
) or the procedure ends. • I don’t use threads, only subprocesses. • The only thing suspicious is a break by with-limits
(from racket/sandbox
), which, due perhaps to sandboxing, may have a different behaviour regarding custodians? I can certainly use a custodian, but before that I feel like I’m not understanding something about my program (while I do understand the guide sections you point to), and that some file ports are not closed somehow while I expect them to be closed

Looking at the source, write-to-file
, file->value
and friends do use call-with-[out/in]put-file*
so the ports should be closed automatically even if an exception is raised. Clearly I’m missing something.


It might be bad advice, sorry. My thinking was that racket/sandbox
does a lot and is maybe a bit “heavy” way to get a timeout — maybe not add too many more moving parts, when you’re already seeing some puzzling behavior. So I thought about building up what you need, from smaller pieces, which made me think of that link.

oh I understand where you’re coming from now. Thanks. with-limits
is pretty much what I need (for now I need only the time, but I’m likely to use the memory limit later too). Using a custodian does seem to work (for now at least), but I’m still looking for what goes wrong. I could try removing with-limits
indeed.

There is a pkg-name
field, but AFAIK it’s only used by create-dirs-catalog
—maybe it should be used more? You can supply —name
at the command line, but that requires anticipating this problem.

Hi, I believe Typed Racket will be more type safe. It is safer to redefine car as follows: #lang typed/racket
;; Remove (All (a) (-> (Listof a) a)) type.
(: safe-car (All (a b) (-> (Pairof a b) a)))
(define safe-car car)
(provide (rename-out [safe-car car]))
Has anyone else thought the same thing I have in the past? I would prefer to use such a library of safe procedures if it already exists.

Sorry, I don’t quite understand what you are trying to accomplish? Can you elaborate a bit more?

FWIW, the actual type of car
that typed/racket
provides is:
(All (a b) (case-> (-> (Pairof a b) a) (-> (Listof a) a)))
which is both (All (a) (-> (Listof a) a))
and (All (a b) (-> (Pairof a b) a))
at the same time, and it will pick one that makes sense to be used.

So I’m not sure what you mean by “more type safe”

Thank you for your response.
I have a problem with the following procedure to pass the type test. #lang typed/racket
(define (test-procedure)
(car '()))

Dynamic error when applying car
to an empty list.
The following is a type error: #lang typed/racket
(: safe-car (All (a b) (-> (Pairof a b) a)))
(define safe-car car)
(define (test-procedure)
(safe-car '()))

Ah, yes.
My guess is that it’s a trade-off between accepting some faulty programs to reduce false positive errors, or rejecting faulty programs but has more false positive errors. @samth probably knows better.

(and also @capfredf)

I prefer the current Typed Racket’s type for typing existing untyped code. However, when writing a new program in Typed Racket I would like to eliminate dynamic errors as much as possible.

OCaml can “warn” me if a program pattern match has been not exhaustive. let rec append lst1 lst2 = match lst1 with
\| (head::tail) -> head :: (append tail lst2)
$ ocaml <http://test.ml\|test.ml>
File "./test.ml", lines 1-2, characters 27-46:
1 \| ...........................match lst1 with
2 \| \| (head::tail) -> head :: (append tail lst2)
Warning 8 [partial-match]: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
[]
Changing car
to safe-car
and cdr
to safe-cdr
achieves almost the same thing as a Typed Racket. In addition, Typed Racket is safer because it results in a type error instead of warning. However, since we are forced to test for non null?
in order to apply safe-car
and safe-cdr
, I think that the trade-off between complexity and safety is unavoidable.
For example: #lang typed/racket
(: safe-car (All (a b) (-> (Pairof a b) a)))
(define safe-car car)
(: safe-cdr (All (a b) (-> (Pairof a b) b)))
(define safe-cdr cdr)
;; ;; Type Error
;; (: bad-append (All (a) (-> (Listof a) (Listof a) (Listof a))))
;; (define (bad-append lst1 lst2)
;; (cons (safe-car lst1)
;; (bad-append (safe-cdr lst1) lst2)))
;; Pass type checker. Causes a dynamic error.
(: bad-append/car-and-cdr (All (a) (-> (Listof a) (Listof a) (Listof a))))
(define (bad-append/car-and-cdr lst1 lst2)
(cons (car lst1)
(bad-append/car-and-cdr (cdr lst1) lst2)))
;; Pass type checker.
(: good-append (All (a) (-> (Listof a) (Listof a) (Listof a))))
(define (good-append lst1 lst2)
(if (null? lst1)
lst2
(cons (safe-car lst1)
(good-append (safe-cdr lst1) lst2))))
Ideally, a language like #lang typed/racket/safe
make me happy. But, I think it would be difficult to eliminate the danger of zero division from a procedure like /
, and I think it would be difficult to achieve perfection.