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.

Reply via email to