
how come impersonator contracts are “wrong” on immutable struct fields but perfectly acceptable on list elements? what makes an immutable list different from an immutable struct?

@leif I don’t remember for sure, but I think it’s needed to have fonts when the host doesn’t otherwise have any fonts installed.

@notjack everyone has access to the cons
constructor

@samth I don’t follow at all

thinking through this more - is the important part that a struct/c
contract on an instance of the structure type break invariants imposed by the guard procedure of the type?

I’m seeing that there exists impersonate-struct
, chaperone-struct
, and chaperone-struct-type
but no impersonate-struct-type
which seems related

Yes that’s right (or just by hiding the constructor)

if you’re given an immutable structure value with 1 and 2 in the fields, you can’t in general produce a similar struct with 3 and 4 as the field values

while obviously if you have a pair with 1 and 2, it’s easy to write (cons 3 4)

So if I had a geometry library with a (point x y)
struct and provided a (point/c x-contract y-contract)
combinator that allowed impersonator contracts, somebody could just make an impersonator contract that turns (point 1 2)
into (point 'general 'nonsense)
and explode my library code that internally uses unsafe math ops on point fields because it assumes they’re always numbers.

yes

if I never allow chaperones / impersonators on specific instances of a struct, is it safe to allow impersonation in the struct type constructor? (ignoring subtyping)

concretely this came up a long time ago for me because I wanted an optional
/ maybe
type with an optional/c
contract combinator that allowed parametric contracts

and I couldn’t figure out how to do that beyond just shrugging and making the field of the internal optional struct mutable

yes, i think so

@samth Related line of inquisition: I noticed that the data/order
and data/enumeration
libraries actually carry the component contracts around explicitly with the order / enum and give you functions to access them. I’ve taken to doing that for most of my uses of contracts lately, but in a way where the constructors don’t accept contracts and the combinators make contracts that implicitly add the component contracts to the value after chaperoning / impersonating. So I’ll end up with an API that looks something like this:
make-frobnicator : {{some function or whatever}} -> frobnicator?
frobnicator/c : (-> contract? contract?)
frobnicator-domain : (-> frobnicator? contract?)
frobnicate! : (->i ([frob frobnicator?] [v (frob) (frobnicator-domain)]) [_ void?])
I was able to do this a few ways: one, I made my own impersonator properties containing the contracts and stuck them in various places; two, I made separate struct types like chaperone-frobnicator
and impersonator-frobnicator
that have the extra contracts and work correctly with chaperone-of?
and impersonator-of?
; and three, I used one frobnicator
struct with fields for the contracts that default to no contract and overrode gen:equals+hash
to just ignore those contract fields so chaperone-of?
and impersonator-of?
work automatically. Do any of those approaches sound broken? Does one seem obviously better than the others to you?

I don’t see anything particular better or worse, but the authors of those libraries (such as @robby or @maxsnew) might have more ideas

The enumerators use the contracts because the contracts are a handy way to express what the enumerators actually enumerate.

The paper on the enumerators library was very helpful

Maybe I should write this up in a racket users post with more examples

eventually

@samth just realized something about the point/c
example: what if I placed contracts… on the field contracts? Like, allowed impersonation but enforce that the impersonator contracts always return numbers

I don’t know if that’s possible for contracts

I think it is - probably by making something like (contract/c in out)
that wraps a contract with one that checks what it’s used on and what it returns

Hi all,

I’m trying to create a predicate in typed racket to assert types.

Above is the best solution I can come up with but sadly it doesn’t work that way.

Are you familiar with define-predicate
?

not yet. Let me google it.

Don’t use google, use the Racket docs search: http://docs.racket-lang.org/search/index.html?q=define-predicate

thanks


As I understand the docs I should be able to do something like this but … no way.

You need (define-predicate list-of-string? (Listof String))
; the grammar in the docs is (define-predicate name t)
.

forgot the name! works!

sry was confused by make-predicate

awesome, that was zero work

let’s see if it works for my super-duper data-structures…

Type Checker: Type Selectivity-Data could not be converted to a predicate: required a flat contract but generated a chaperone contract in: Selectivity-Data

what is Selectivity-Data
?


sry for spamming you with code and error messages

hashes and vectors can be mutable, so, for example, even if a hash contains only string keys and list values when you test a predicate, it might be modified by another thread

so I need an immutable hash instead?

and that other thread might insert a non-string key or a non-list value. so TR refuses to accept the predicate.

I think there are immutable hash types in TR now, but I don’t think there are immutable vector types. I could be wrong, though.

Maybe I can work around it by making the vector something else.

So the hash needs to be immutable and the vector needs to go away, maybe I can do that.

if you are just using the vector to store pairs, lists or cons pairs should be fine, which are immutable.

there are immutable hashtables btw

it should work if you change the type to (Immutable-HashTable String (Listof (List Real Real)))
.

it depends on what plot
wants. but I think I remember, it expects only a sequence there

that’s what I’ll try, thanks for the hint in any case.

the (Listof (Vector Real Real))
goes into points
eventually.

a workaround for this in general is to use a struct instead of a type alias. so if you do (struct selectivity-data ([value : (HashTable String (Listof (Vector Real Real)))]))
then use selectivity-data?
, then TR will treat that as sufficient evidence that selectivity-data-value
will produce the type you want.

really? how does it make a difference to wrap it in a struct?

this is because constructing a selectivity-data
structure imposes a requirement on the caller that the value has a sufficiently restrictive type, so the predicate selectivity-data?
only needs to check the tag (the wrapper struct) to know the guarantee was met, rather than inspect the data inside.

interesting

when you use the value in typed code, the type system will ensure you can’t break the guarantee, and if the data crosses a typed/untyped boundary, TR will wrap it in a contract that ensures the guarantee will hold.

that is useful to know, some day I might not be able to work around mutable hash-tables and vectors.

as always, you are a big help! thank you so much.