define/contract for private functions

33 views
Skip to first unread message

Ryan Kramer

unread,
Jul 23, 2019, 12:08:15 PM7/23/19
to Racket Users
I've found myself wanting to write contracts on private functions, but I don't want to pay the performance cost during normal operation. What I've been doing is making a `def/c` macro which looks exactly like `define/contract` but is wired up to `define` and discards the contract. When I want to enable these private contracts (e.g. when running tests or debugging a problem) I simply change the source code of `def/c` so that it is wired up to `define/contract` and the contract is checked. Here is an example: http://pasterack.org/pastes/4224

Manually changing the source code of `def/c` has worked fine so far, but I would love to be able to do something like "raco test -with-private-contracts (package1, package2) ./" instead.

I prefer this approach over putting the contracts in comments, because comments have less precise meaning and may become subtly inaccurate if the implementation of the function changes.

I wonder if other people want to write code the same way. If so, having a standard, shared `define/contract/private` could be useful. This would allow us to do things like
1) Build a contract-aware linter.
2) Build a "minimally intrusive type system." (This might also be called a "linter"; I'm not sure if there is a definite line separating the two.)
3) Better IDE support
4) If I suspect a package I am using has a bug, I might be able to confirm (but not deny) that suspicion by turning on private contracts for that package and seeing if a violation is reported.

So I guess if I'm the only one interested in this then just ignore me. If there's already work in this area, great! Please point me to it. But if there's interest and a need, I'd be happy to help however I can.

Bogdan Popa

unread,
Jul 23, 2019, 12:17:16 PM7/23/19
to Ryan Kramer, Racket Users

> When I want to enable these private contracts (e.g. when running tests or
> debugging a problem) I simply change the source code of `def/c` so that it
> is wired up to `define/contract` and the contract is checked. Here is an
> example: http://pasterack.org/pastes/4224

You can run arbitrary code in macros so you could use environment
variables to achieve this. For example:

(define-syntax-rule (def/c head contract body ...)
(if (getenv "PRIVATE_CONTRACTS")
(define/contract head contract body ...)
(define head body ...)))

And then run your code with

env PRIVATE_CONTRACTS=x racket some-module.rkt

The drawbacks to this approach is it makes compilation significantly
slower and, once code is compiled (via raco setup, raco make or raco pkg
install), the flag stops having any effect -- the code is compiled
according to whatever the environment looks like at compile time and
then maintains that behavior until it is recompiled.

Roman Klochkov

unread,
Jul 24, 2019, 1:55:58 AM7/24/19
to Racket Users
I propose to use submodules like in https://github.com/Kalimehtar/binary-class/blob/master/binary-class/base.rkt

So you may in test module (require mod/safe) and in normal operation (require mod).

вторник, 23 июля 2019 г., 21:08:15 UTC+5 пользователь Ryan Kramer написал:

Ryan Kramer

unread,
Jul 24, 2019, 11:07:25 AM7/24/19
to Racket Users
On Wednesday, July 24, 2019 at 12:55:58 AM UTC-5, Roman Klochkov wrote:
I propose to use submodules like in https://github.com/Kalimehtar/binary-class/blob/master/binary-class/base.rkt

So you may in test module (require mod/safe) and in normal operation (require mod).

Sorry, I wasn't clear what I meant by "private function." I am talking about functions that are not provided anywhere (e.g. they are only available in one source file). These functions often have comments like

;; integer symbol -> string

But making them contracts instead of comments can provide some benefits that I mentioned earlier.
Reply all
Reply to author
Forward
0 new messages