It isn’t wrapped in an opaque structure. That wasn’t a part of my proposal, and 
while I didn’t think of it until you brought it up, I still think it’s 
unnecessary and doesn’t add any convenience.

Perhaps I’m not understanding you properly, but your “one-length string” idea 
sounds like it has little to do with this opaque type problem and more to do 
with the fact that you want refinement types in Typed Racket. I do, too! But I 
don’t think hacking the opaque type system is going to help you with that.

(Also, as for the box example, I’m actually a little surprised that doesn’t 
contract error. Seems like a bug to me, but perhaps I’m missing some 
idiosyncrasies of the type system. Either way, it’s precisely that kind of 
craziness I was referring to when I compared casting parametric opaque types to 
casting mutable types.)

> On Jan 29, 2015, at 20:50, Alexander D. Knauth <alexan...@knauth.org> wrote:
> 
> 
> On Jan 29, 2015, at 11:34 PM, Alexis King <lexi.lam...@gmail.com 
> <mailto:lexi.lam...@gmail.com>> wrote:
> 
>>> But the problem is that if it’s an opaque type then it can’t unwrap it once 
>>> the value is returned from make-posn.
>> 
>> Yes, that’s precisely the problem. Your point about implementing everything 
>> as single-valued structs on the typed side is an interesting one, though I 
>> don’t think it ultimately solves any problems. The fact that the typed side 
>> knows nothing about the contents of the value is what makes this such a 
>> tricky problem.
>> 
>> As for this:
>> 
>>> But then you couldn’t do any operations on it except those that you use 
>>> import with require/typed, right?
>> 
>> That’s completely correct. That’s why it’s “opaque.”
>> 
>>> And what happens if you use cast on one of these things?
>> 
>> That’s a little more interesting. Using cast on an object of this type would 
>> never fail (unless, of course, it didn’t actually satisfy the basic posn? 
>> predicate), but it would possibly introduce failures in the future since it 
>> would affect the contracts generated for posn-x and posn-y, for example.
>> 
>> To make that more clear, casting a (Posn Real) to a (Posn String) would work 
>> fine until you tried to call posn-x on the instance, in which case it would 
>> raise a contract error. Note that this isn’t really any different from 
>> casting mutable data types.
> 
> But if it were wrapped in an opaque structure, then that structure wouldn’t 
> satisfy the posn? predicate, unless of course the posn? predicate has a 
> contract that unwraps it.  So all of the operations on it would have to have 
> contracts that would unwrap it.  This might actually make sense if the type 
> is meant to be actually opaque, but if it’s an opaque type that represents a 
> normal non-opaque value, then it will still work as an opaque type, but it 
> won’t be a normal non-opaque value anymore on the typed side.  
> 
> But the reason I asked about cast was because normally I can use cast with a 
> value that has an opaque type, but it’s wrapped on the typed side in this 
> opaque structure, then the contracts on the cast would see this opaque 
> structure instead of the actual value.  
> 
> I’m thinking of an opaque typed representing a string with length 1, which I 
> can use as long as I use either (cast x String) or (assert x string?) 
> whenever I pass it to a string operation.  But if it were an opaque type, I 
> don’t think I could do that.  There could be a 1string->string function that 
> could take one of these 1strings and convert it to a string, but that seems 
> like it should be unnecessary, but made necessary by this opaque structure 
> thing.  
> 
> And for “this isn’t really any different from casting mutable data types,” 
> look at this:
> #lang typed/racket
> (: b : (Boxof Number))
> (define b (box 1))
> (set-box! (cast b (Boxof (U Number String))) "I am a string")
> (ann (unbox b) Number) ;"I am a string” ; not a contract error
> 
> 
>> 
>>> On Jan 29, 2015, at 20:20, Alexander D. Knauth <alexan...@knauth.org 
>>> <mailto:alexan...@knauth.org>> wrote:
>>> 
>>> Furthermore, even if the wrappers were shared between functions, untyped 
>>> code would recieved wrapped values, which would render them quite useless.
>>> 
>>> If it’s not an opaque type, but something like a list, then this works, and 
>>> the untyped code receiving wrapped values isn’t a problem here:
>>> #lang typed/racket
>>> ; make Posn parametric
>>> (define-type (Posn A) (List A A))
>>> (provide Posn)
>>> (require/typed/provide
>>>  "untyped.rkt"
>>>  [make-posn (All (A) A A -> (Posn A))]
>>>  [posn-x (All (A) (Posn A) -> A)]
>>>  [posn-y (All (A) (Posn A) -> A)]
>>>  [real-posn? [(Posn Any) -> Boolean]])
>>> > (define p (make-posn 1 2))
>>> (make-posn #<A6> #<A6>) ; a printf that I put in make-posn from 
>>> “untyped.rkt"
>>> > p
>>> - : (Listof Positive-Byte) [more precisely: (List Positive-Byte 
>>> Positive-Byte)]
>>> '(1 2) ; unwrapped
>>> > (posn-x p)
>>> - : Integer [more precisely: Positive-Byte]
>>> 1
>>> > (posn-y p)
>>> - : Integer [more precisely: Positive-Byte]
>>> 2
>>> > (real-posn? p)
>>> - : Boolean
>>> #t
>>> 
>>> Even though for a short time it's wrapped, it’s unwrapped as soon as 
>>> make-posn returns, and then after that if it flows into untyped code again 
>>> it’s not wrapped and functions like real-posn? work fine.  
>>> 
>>> But the problem is that if it’s an opaque type then it can’t unwrap it once 
>>> the value is returned from make-posn.
>>> 
>>> And I don’t think parametric opaque types could solve this unless all posns 
>>> themselves were wrapped with an opaque struct on the typed side, which I 
>>> guess does make sense now that I think about it.  But then you couldn’t do 
>>> any operations on it except those that you use import with require/typed, 
>>> right?  Or not?  And what happens if you use cast on one of these things?
>>> 
>>> 
>>> On Jan 29, 2015, at 9:25 PM, Alexis King <lexi.lam...@gmail.com 
>>> <mailto:lexi.lam...@gmail.com>> wrote:
>>> 
>>>> I recently ran into a problem in which opaque types (types imported from 
>>>> untyped code) cannot by parameterized by Typed Racket. I initially 
>>>> encountered this problem in my attempt to port 2htdp/image to TR 
>>>> <https://github.com/lexi-lambda/racket-2htdp-typed/issues/1>.
>>>> 
>>>> After some further consideration, I’m interested in adding support to make 
>>>> something like this possible, which would certainly have additional 
>>>> benefits beyond this specific use-case. I’ve outlined my proposal here:
>>>> http://lexi-lambda.github.io/racket-parametric-opaque-types/ 
>>>> <http://lexi-lambda.github.io/racket-parametric-opaque-types/>
>>>> 
>>>> Any feedback, suggestions, or advice would be appreciated, especially from 
>>>> those who are familiar with Typed Racket’s internals.
>>>> 
>>>> Thank you,
>>>> Alexis
>>>> _________________________
>>>>  Racket Developers list:
>>>>  http://lists.racket-lang.org/dev <http://lists.racket-lang.org/dev>
_________________________
  Racket Developers list:
  http://lists.racket-lang.org/dev

Reply via email to