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

-- 
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/a28f5e1e-93e2-d16d-48ab-32168dd42745%40sagegerard.com.

Reply via email to