laurent.orseau
2022-3-18 09:19:11

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


laurent.orseau
2022-3-18 09:30:55

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.


laurent.orseau
2022-3-18 09:47:36

greg
2022-3-18 15:28:20

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.


laurent.orseau
2022-3-18 15:41:59

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.


philip.mcgrath
2022-3-18 15:45:09

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.


account
2022-3-19 03:07:34

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.


sorawee
2022-3-19 03:49:34

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


sorawee
2022-3-19 03:52:19

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.


sorawee
2022-3-19 03:52:53

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


account
2022-3-19 03:54:06

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 '()))


account
2022-3-19 03:56:53

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 '()))


sorawee
2022-3-19 03:56:59

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.


sorawee
2022-3-19 03:57:44

(and also @capfredf)


account
2022-3-19 04:06:36

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.


account
2022-3-19 05:10:52

OCaml can “warn” me if a program pattern match has been not exhaustive. let rec append lst1 lst2 = match lst1 with \| (head::tail) -&gt; 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) -&gt; 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) (-&gt; (Pairof a b) a))) (define safe-car car) (: safe-cdr (All (a b) (-&gt; (Pairof a b) b))) (define safe-cdr cdr) ;; ;; Type Error ;; (: bad-append (All (a) (-&gt; (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) (-&gt; (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) (-&gt; (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.