
@jsn has joined the channel

hi there. Is this a proper place for raising potential bugs?

I believe it’s fine to discuss here any issues you have.

@jsn

the following fails in the second test only. I wouldnt believe that copying should be dependant on the struct-options (#:transparent) ?! #lang racket/base (require rackunit) (struct Mystruct1 (x y) #:transparent) (struct Mystruct2 (x y)) (define (mycopy1 x) (struct-copy Mystruct1 x)) (define (mycopy2 x) (struct-copy Mystruct2 x)) (define X1 (Mystruct1 1 2)) (define X2 (Mystruct2 1 2)) (module+ test (check-equal? X1 (mycopy1 X1)) (check-equal? X2 (mycopy2 X2))) ;;<- fail here.
. FAILURE name: check-equal? location: struct-bug.rkt:16:2 actual: #<Mystruct2> expected: #<Mystruct2>

Yes, the #:transparent
option does make a difference.

is it a bug or a feature?

The last paragraph on this page https://docs.racket-lang.org/reference/structures.html?q=struct clarifies that structs are only equal if their types are the same, fields are not opaque, and result of struct->vector
are the same. In your case, Mystruct2 instances fields are opaque

well it’s by design, though I don’t know why it’s designed that way.

yes, quite strange. I have a Very-Large-Struct so I decided to have it not #:transparent so I wouldnt print it by accident..

you can customize printing regardless of whether or not a struct is opaque


well as far as I can gather, the idea is to control how structs can be “inspectable” equal?
works by default if struct is #:transparent
otherwise you can provide your own equality by using the gen:equal+hash
generic interface

for opaque structs or to override the default #:transparent
equality

my simple understanding: an opaque struct can act as an arbitrary abstraction / a transparent struct exposes much more of its internal structure to anyone who can get their hands on it

I believe there have been comments that #:transparent
may have been a better default (instead of opaque) when declaring a struct (could be wrong or there may have been more to it)

but that comment was a “hind-sight” comment if I recall

yes I have come across archived discussions about how in retrospect #:transparent
was the right default behavior, oh well. We have to live with past design choices.

struct
is used heavily in the Racket ecosystem, in the infrastructure implementations so it has accumulated a lot of add-ons and behaviors that seem inexplicable to typical application programmers. I only have used the basic struct features, haven’t had the need to use the more obscure features.

thanks @abmclin @pnwamk I will try and see if I can work around this using gen:equal+hash The point here was not so much the printing of the struct it self, it was more not being able to compare ‘like’ to ‘like’ when the struct is not #:transparent.

@joslarki has joined the channel

is or/c
associative for “good” contracts? i.e. is (or/c A B C)
the same as (or/c A (or/c B C))
and (or/c A (or/c B (or/c C)))
….

(by “good” I’m thinking “no state”)

@robby would know for sure, but i would worry about flat vs ho contracts

@ben I think it is associative regardless of the good or badness of A, B, and C. (Assuming they evaluate to contracts, and you are not doing any especially weird things in combinatory you write outside the contract system).

hm, I found an example where adding an inner or/c
can lead to an exception — because it delays a flat contract that would pass: > (define ctc0 (or/c (-> boolean?) procedure? (-> string?)))
> (define ctc1 (or/c (-> boolean?) (or/c procedure? (-> string?))))
> (contract ctc0 void 'pos 'neg)
#<procedure:void>
> (contract ctc1 void 'pos 'neg)
; readline-input:4:0: broke its own contract
; two of the clauses in the or/c might both match: (-> boolean?) and (or/c
; procedure? (-> string?))

(but so far, no reason typed racket shouldn’t flatten nested or/c
s in the contracts it makes)

@ben @robby I don’t understand why it’s ok to apply ctc0
to void
there, don’t the first order checks of the 2 -> contracts overlap?

Yes I agree with Dan

Looks buggy

Oh I know why

I have the wrong answer upthread.

It isn’t associative unless all of the flat contracts come first (or they are all flat or none are)

@robby shouldn’t the first example above error also though? I thought or/c applied the first order checks to disambiguate the higher order contracts? or is it that it short circuits if a flat contract would succeed first?

I can still get an error if all the flat contracts come first > (define ctc0 (or/c procedure? (-> boolean?) (-> string?)))
> (define ctc1 (or/c (or/c procedure? (-> boolean?)) (-> string?)))
> (contract ctc0 void 'pos 'neg)
#<procedure:void>
> (contract ctc1 void 'pos 'neg)
; readline-input:4:0: broke its own contract
; two of the clauses in the or/c might both match: (or/c procedure? (->
; boolean?)) and (-> string?)

@dan I’m using or/c
to “change the answer” of contract-first-order

Or/c first collects all flat ones and then checks them. Only if they fail to pass does it look at the ho ones.

I see what you mean, Ben, so my wording was bad.

@robby ok, that makes sense and now I understand why ctc0
is successfully applied in both of @ben’s examples

I guess, it’s associative if it doesn’t group a flat contract with a chaperone?

Something like that

Maybe or/c is the wrong combinator for TR

Maybe it should use something less “clever”

maybe, but I think I can turn this into a useful simplification rule for now

if there’s a nested or/c
and all its members are flat, then it can definitely be un-nested

Yes

There may be more general rules too

In the case above it seems surprising that TR would generate such a contract

yeah, definitely