The Racket repository
![]() avoids piling up redundant instanceof/c contracts This is not a general purpose solution, but instead a hack that covers certain hopefully likely patterns of redundant contracts for objects. This commit looks for redundant contracts according in a slightly more general pattern than just "is the most recently attached contract stronger than the one I'm about to put on here and does it have the same blame labels?", because that predicate isn't good enough to cover the example below. In the example below, we repeatedly get the same contract put on an object, but with different blame labels. So we need to drop "inner" contracts. That is, when we have two contracts on there and we go to add the third, we can tell that the second one would no longer ever signal blame, so we can keep just the first in the third. More concretely, if we had these two contracts on 'v' with the given blame labels (higher lines means the contract is "outside" or applied later and the blame labels are in positive/negative order): (-> x y) <c,d> (-> x y) <a,b> then the two possible blames we get here are blaming d for a non-x argument and blaming a for a non-y result. And now lets say we add a third contract to the stack that's a copy of the first, but possibly with different blame labels: (-> x y) <e,f> (-> x y) <c,d> (-> x y) <a,b> Now we can blame f for non-x argument and a for a non-y result, both of which are things covered by the first and third contract, so we can safely drop the middle one and use this stack: (-> x y) <e,f> (-> x y) <a,b> The example above is couched in terms of arrow contracts, but this commit doesn't do this for arrow contracts, it does it for instanceof/c contracts. And also the way that we tell that the inner contract is redundant isn't that it is equal; instead we use contract-stronger?. In particular, the above reasoning works, I believe, when we have that the inner contract is stronger than the one we're removing and when the outer contract is also stronger than the one we're removing. That's the check that actually happens in the code. ------- The code below is the example below is an example Asumu sent me (but with the TR parts stripped out). Before this commit, the contract wrapping grows without bound, but with this commit it stays constant. In the example below we get only two different sets of blame labels (and equal contracts) and thus are actually more contracts that could be eliminated, but this commit does limit it to just two contracts. (I think it could be alternating between one and two contracts instead of always two if the code that dropped the contracts were more clever.) #lang racket/base (module State racket/base (require racket/contract racket/class) (define state/c (recursive-contract (class/c [m (-> any/c (instanceof/c state/c))] [n (-> any/c (instanceof/c state/c))]))) (define state% (class object% (super-new) (define/public (m) (send this n)) (define/public (n) (new state%)))) (define (tree-next o) (send o m)) (define (make-tree) (new state%)) make-tree (provide (contract-out [tree-next (-> (instanceof/c state/c) (instanceof/c state/c))] [make-tree (-> (instanceof/c state/c))]))) (require (submod "." State)) (require racket/sandbox) (with-limits #f 100 (let loop ([o1 (make-tree)] [n 0]) (printf "~a\n" n) (define o2 (tree-next o1)) (loop o2 (add1 n)))) |
||
---|---|---|
native-pkgs@2f116c1b64 | ||
pkgs | ||
racket | ||
.gitattributes | ||
.gitignore | ||
.gitmodules | ||
.mailmap | ||
.travis.yml | ||
INSTALL.txt | ||
Makefile | ||
README.txt |
This is the source code for the main Racket distribution. See "INSTALL.txt" for information on building Racket. License ------- Racket Copyright (c) 2010-2014 PLT Design Inc. Racket is distributed under the GNU Lesser General Public License (LGPL). This means that you can link Racket into proprietary applications, provided you follow the rules stated in the LGPL. You can also modify Racket; if you distribute a modified version, you must distribute it under the terms of the LGPL, which in particular means that you must release the source code for the modified software. See racket/src/COPYING_LESSER.txt for more information.