Almost forgot, just in case someone asks: I want to avoid checking for invariant violations when I print. That would entail checking a bunch of values in accumulated program output, where it would be awkward to do something non-printing related, let alone raise an error. When I am printing logs, all invariant violations come down to what went a constructor, because all program output is encoded as prefab structures. That's why I want to raise any errors on instantiation.
On 5/9/21 8:55 PM, Sage Gerard wrote: > Of course, if you're okay with a longer email. Before that, thank you both > for volunteering your time to code something out. I enjoyed running into a > `define-module-boundary-contract` in the wild for the first time. > > I sometimes print output in a (read)able form because I like analyzing my > logs. The data I print includes prefab structures, with type ids matching the > topic they cover or the statements they make. You can see that I declare > prefab structure (sub)types cutely labeled "messages" here. [1] > > The idea is that I can either print (for example) a $package:output:built > instance as a localized string, or just toss the instance itself into > writeln. When I read instances back from a port, the struct accessors will > help me filter and match. Hopefully all this shows where my head is. > > Now for the problem. Look at [2], but don't worry about what it means. I just > wanted you to see the constructor call in the exception handler. If I made a > mistake and wrote that line such the exception was placed directly in the > instance, then I wouldn't be able to (read) that instance back later! I > cannot allow #<...> forms in my output, or some symbol soup that happens to > be readable, but doesn't constitute the value it used to be. > > TL;DR I want to protect the invariant `(equal? V (read (open-input-string (~s > V))))` for each V I print to an output port. > > Finally, as to why I didn't want the module boundary contract. The module > that declares prefab structure types is also primarily responsible for > creating all instances of those types. I rarely cross module boundaries when > applying the constructors. > > [1]: https://github.com/zyrolasting/xiden/blob/master/package.rkt#L49 > [2]: https://github.com/zyrolasting/xiden/blob/master/security.rkt#L100 > > On 5/9/21 8:02 PM, Philip McGrath wrote: > >> Here's another minimally-tested sample implementation. A more robust >> solution might try to chaperone the struct type, as well, to protect >> reflective access to the constructor—but I wonder if that really makes sense >> when you are working with prefab structs. If you can explain more about your >> requirements, it might be possible to suggest better approaches. >> >> On Sun, May 9, 2021 at 7:57 PM Ryan Culpepper <[email protected]> wrote: >> >>> I'm not clear on what constraints you're working under with respect to >>> modules, but hopefully you can adapt this to your needs. >>> >>> One option is to use a combination of `define-module-boundary-contract` (or >>> `define/contract`) and `define-match-expander` to bind a name that can be >>> used as a contracted constructor and as a match pattern. (If you want to >>> extend the struct type, though, you still need to use the real one.) >>> >>> Another option would be to "forge" a new compile-time struct-info based on >>> the original struct-info but replacing the constructor. >>> >>> Minimally tested sample implementations attached. >>> >>> Ryan >>> >>> On Mon, May 10, 2021 at 12:23 AM Sage Gerard <[email protected]> wrote: >>> >>>> I have a project with 57 prefab structure types. I need to construct >>>> instances using a local contract (module level contracts do not fit my >>>> needs here). Since I cannot define guards, the solution is easy enough. >>>> >>>> (struct foo (num) #:prefab) >>>> (define/contract make-foo (-> real? foo?) foo) >>>> >>>> Problem: I already have a few hundred constructor calls without contracts. >>>> I could either A) rewrite them all to use contracted constructors, or B) >>>> attach local contracts in a sweet spot so that I don't have to rewrite >>>> anything else. >>>> >>>> I prefer option B, but it doesn't look like I can attach a local contract >>>> to a constructor with `struct` alone, or even with an impersonator. When I >>>> hack around to rebind or hide the constructor's identifier, I break >>>> compatibility with `match` and `defstruct*`. >>>> >>>> If you were in my position, what would you do? >>>> >>>> -- >>>> >>>> ~slg >>>> >>>> -- >>>> You received this message because you are subscribed to the Google Groups >>>> "Racket Users" group. >>>> To unsubscribe from this group and stop receiving emails from it, send an >>>> email to [email protected]. >>>> To view this discussion on the web visit >>>> [https://groups.google.com/d/msgid/racket-users/0a16cfbe-4789-a939-796e-5f6f9da21626%40sagegerard.com](https://groups.google.com/d/msgid/racket-users/0a16cfbe-4789-a939-796e-5f6f9da21626%40sagegerard.com?utm_medium=email&utm_source=footer). >>> >>> -- >>> You received this message because you are subscribed to the Google Groups >>> "Racket Users" group. >>> To unsubscribe from this group and stop receiving emails from it, send an >>> email to [email protected]. >>> To view this discussion on the web visit >>> [https://groups.google.com/d/msgid/racket-users/CANy33qmngGoVoAok6%2BR885jkh8MroMqYHpOd6XtjCSH7iiESQA%40mail.gmail.com](https://groups.google.com/d/msgid/racket-users/CANy33qmngGoVoAok6%2BR885jkh8MroMqYHpOd6XtjCSH7iiESQA%40mail.gmail.com?utm_medium=email&utm_source=footer). > > -- > ~slg -- ~slg -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/7856bfbf-6bd4-c77e-eece-f114987d1872%40sagegerard.com.

