-
-
Notifications
You must be signed in to change notification settings - Fork 102
add separate read and write types for Box types #225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Still need to make a constructor for the more general box type, and fix printing to use that. What should it be called? (Edit: Resolved) |
bd66cbf
to
14d0898
Compare
@@ -531,8 +531,8 @@ | |||
[((Channel: t) (Evt: t*)) (subtype* A0 t t*)] | |||
[((Async-Channel: t) (Evt: t*)) (subtype* A0 t t*)] | |||
;; Invariant types | |||
[((Box: s) (Box: t)) (type-equiv? A0 s t)] | |||
[((Box: _) (BoxTop:)) A0] | |||
[((Box: s-w s-r) (Box: t-w t-r)) (subtypes* A0 (list t-w s-r) (list s-w t-r))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may want to move those out of the invariant types
section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok done.
Re more general type: You mean the constructor that exposes both type arguments? I don't know how much sense it would make to expose that. I'm also not 100% clear on the use case. You mentioned better support for unions of box types, and I remember a discussion on IRC last week on that topic, but the particular example in that discussion left me unconvinced. Would you mind elaborating a bit? FWIW, ISTR @ntoronto wanting something similar for vectors, to have a nicer API for the math library. I think he ended up going with arrays as functions (which have the right variance) to work around that. Aside from the comments, implementation looks good. |
When I said "unions of box types," I was really thinking in my head "unions of vector types, when I do the same thing for vectors." For that I was thinking of this discussion on the mailing list, which started as talking about |
I was also thinking of read-only boxes as |
6c3a511
to
c0d7641
Compare
Re more general type: For example (All (a)
(-> (Unknown
Type:
#(struct:Box
1416
#(struct:combined-frees #hasheq((a . #(struct:Contravariant))) ())
#(struct:combined-frees #hasheq() ())
#f
box
a
Any))
a
Void)) Where it should really be: (All (a) (-> (Box/Write-Read a Any) a Void)) Is |
Ah, that makes sense. |
I wanted (Though I'm also wondering, would changing |
Usually, |
Write before read is consistent with |
Oh, ugh. In regular English, though, "read" usually goes before "write"... |
Would a set of types like this make sense? (Boxof/Write-Read w r) ; can write w, read r
(Boxof/Write w) ; = (Boxof/Write-Read w Any)
(Boxof/Read r) ; = (Boxof/Write-Read Nothing r)
(Boxof t) ; = (Boxof/Write-Read t t) Or this, depending on what we think is better: (Write-Read-Boxof w r) ; can write w, read r
(Write-Boxof w) ; = (Write-Read-Boxof w Any)
(Read-Boxof r) ; = (Write-Read-Boxof Nothing r)
(Boxof t) ; = (Write-Read-Boxof t t) Would that set of types make sense? Does the |
I prefer the latter. |
I think I prefer the former, but why not just have |
Right now, |
87310ff
to
0199804
Compare
Ok, I just renamed |
c47b668
to
a38d45e
Compare
What do you think? Is it worth another special case in |
Yes, I think it's worth the special case. What do other people think? |
Sure. |
a38d45e
to
e843686
Compare
When |
I don't understand why this is needed. What's different than how pairs work? |
You're right. The analogous case for For merging boxes
Then
Should also work because So I think I need to replace each |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you change the type of immutable?
to have (-Boxof/Read Univ)
as a positive proposition?
(I don't think there's a useful negative proposition)
The second form is a @rtech{box} that supports write operations like | ||
@racket[set-box!] taking @racket[write-t], and read operations like | ||
@racket[unbox] returning @racket[read-t]. For this type to make sense, | ||
@racket[write-t] should be a subtype of @racket[read-t]. This form can |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should "should be" say "must be"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because the type (Boxof A B) A </: B
can still exist, it's just impossible to write an expression that produces a value of that type. (Unless you use cast
or require/typed
, something that guards it with a contract, in which case it's nearly impossible for that value to keep to that contract for everything you could do to it. "nearly" because weird uses of impersonators might be able to fake it, but it doesn't make sense in normal code.)
(match* (t ts) | ||
[((Box: a-w a-r) (list-no-order (Box: b-w b-r) bs ...)) | ||
(define w | ||
;; should this use some sort of intersection, or would that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use intersect
from infer/intersect.rkt
here?
I think that would be better than the cond
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what the implications of using intersect
might be. @pnwamk what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pnwamk In what situations is it appropriate to use intersect
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey sorry -- I'm a little slow coming up to speed on this.
intersect
is supposed to compute the logical "and" of two types (performing some simplifications where possible), so if something is both of type T1
and type T2
, then saying it is of type (intersect T1 T2)
should always be fine.
I guess the only "exception" I can think of is in a few places our handling of intersections is not complete (i.e. at the moment we do not fully handle the application of an intersection of function types -- but this isn't a problem with intersect
or intersection types, it's just a deficiency in our code that handles function application at the moment).
Anyway, did that answer your question?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I'm guessing it is appropriate to use intersect
in normalize-type
to determine the "write" type of the merged result of a union of two box types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Re: #225 (comment))
Okay, I've changed this to use intersect
.
yes
EDIT: nevermind, makes sense to not change |
@bennn No, it wouldn't, because (Boxof String) <: (Boxof/Read String) Speaking of intersections, they weren't there when I first started with this pull request. Should I have to change anything about intersections to handle intersections of boxes? |
@defform[(Boxof/Read t)]{ | ||
A @rtech{box} of @racket[t] that only supports read-only operations | ||
such as @racket[unbox]. A @racket[(Boxof/Read t)] is a subtype of | ||
@racket[(Boxof t)], and a @racket[(Boxof/Read a)] is a subtype of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: (Boxof/Read t)
is not a subtype of (Boxof t)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ll change it to say supertype.
We need to think of how this pull request should handle programs like this. Should we make #lang typed/racket
(define b (box-immutable 5))
(: f : (Boxof Integer) -> Integer)
(define (f b)
(unbox b))
(f b) Typed Racket currently lets this pass, but this pull request makes it a type error, because (Edit: Fixed now, this program passes as it should.) |
I think the point of this PR should be to change what programs people can write, by allowing them to specify read and write types, rather than to change the meaning of existing programs. We definitely shouldn't break that example. |
So (Edit: Fixed now) |
I can’t think of a reason why you should avoid using intersect in
normalize-type. Should be fine!
…On Tue, Jan 2, 2018 at 10:57 AM Alex Knauth ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In typed-racket-lib/typed-racket/types/union.rkt
<#225 (comment)>:
> @@ -30,6 +30,19 @@
(cond
[(subtype t* t) (list t)]
[(subtype t t*) ts]
+ ;; the union of two box types is a box type where the write type has to
+ ;; satisfy both write types, and the read type can satisfy either of the
+ ;; two read types
+ [(and (Box? t) (ormap Box? ts))
+ (match* (t ts)
+ [((Box: a-w a-r) (list-no-order (Box: b-w b-r) bs ...))
+ (define w
+ ;; should this use some sort of intersection, or would that
So I'm guessing it is appropriate to use intersect in normalize-type to
determine the "write" type of the merged result of a union of two box types?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#225 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADfg6jnL87DZkM9nIC0ytCmXo1wEKv0bks5tGlARgaJpZM4GVTsb>
.
|
because otherwise immutable boxes could not be used at that type at all
34ca0be
to
87769eb
Compare
After seeing discussion #1129, I'm thinking this might need a more generalized way of dealing with the opposite-variance-type-pairs for types such as |
The
Boxof
type now has two forms:(Boxof t)
, a type for boxes that can contain values of typet
. You can writet
values into the box withset-box!
, and readt
values from the box withunbox
.(Boxof write-t read-t)
, a type for boxes that only allows writingwrite-t
values withset-box!
, while reading withunbox
producesread-t
.The
write-t
position is contra-variant, and theread-t
position is covariant. Read-only boxes can be expressed with(Boxof Nothing read-t)
, and unions of box types make sense since theread-t
s can be unioned together while thewrite-t
s are restricted.