notjack
2019-3-5 08:12:10

Here’s the most common words, first or otherwise: make 102 syntax 89 hash 62 string 60 module 58 current 56 bytes 56 in 46 path 42 read 38


spdegabrielle
2019-3-5 09:09:50

Half refer to a data-type Care to share your script?


notjack
2019-3-5 09:13:37

Will try to share tomorrow, heading to bed for now


hoshom
2019-3-5 11:35:01

I’m trying to pass a result of query-rows from untyped racket to a function in my typed package. This functions takes a (Listof (Vectorof Any)) and processes it. But I get this error: any-wrap/c: Unable to protect opaque value passed as `Any` Anyone knows how I should work around this?


hoshom
2019-3-5 11:44:41

My case is very similar to the one mentioned here: https://www.mail-archive.com/racket-users@googlegroups.com/msg32201.html


samth
2019-3-5 13:49:45

@hoshom in general using Any is problematic — can you use a more specific type?


343519265
2019-3-5 14:02:06

@343519265 has joined the channel


alexknauth
2019-3-5 16:57:36

@hoshom The Any inside the vector produced by query-rows represents the things that could be in the database. Are those simple values like numbers or strings? Are they existing immutable racket data structures like lists? Are they existing mutable racket data structures like vectors or boxes? Or are they your own datatype that you’re defining to put in the database?


alexknauth
2019-3-5 17:01:36

Or is it sql-null that’s giving you the problem?


soegaard2
2019-3-5 17:26:47

This is pretty clever: “Racket ABNF implementation (interpreter & compiler), for directly cutting-and-pasting from RFCs.”


soegaard2
2019-3-5 17:26:53

bennynguyensg
2019-3-5 17:53:34

@bennynguyensg has joined the channel


lexi.lambda
2019-3-5 17:54:56

@samth can you make it so that people who aren’t admins can’t use @ everyone?


james.swaine
2019-3-5 17:55:27

+1


samth
2019-3-5 17:57:39

I’ll see what I can do but slack moderation tools are not very good


lexi.lambda
2019-3-5 17:57:59

I know, but I do know you can disable @ everyone


hoshom
2019-3-5 18:11:59

@samth @alexknauth I suppose I’ll post on the mailing list; slack doesn’t seem like a very good place for writing any amount of detail.


samth
2019-3-5 18:12:43

@hoshom it’s easier to discuss in real time here, though


hoshom
2019-3-5 18:12:57

oh ok


hoshom
2019-3-5 18:13:06

So yeah mostly the problem is sql-null


hoshom
2019-3-5 18:13:31

What started all this was, I had a type, mostly a union of primitives that I expected to deal with from the database. (U String Number Boolean Char Bytes). Two things that I wanted The moment I added SQL-Null, all functions that dealt with these values started failing.


alexknauth
2019-3-5 18:13:39

Though I think if it was an immutable vector instead of a mutable vector it would be fine


alexknauth
2019-3-5 18:14:19

Because a mutable vector’s “contents” contract is used for both “typed -> untyped” crossings and “untyped -> typed” crossings


hoshom
2019-3-5 18:16:02

So what I did was this: (define-type RawResults (Listof (Vectorof Any))) (define-type ResultRow (Vectorof AnyVal)) (define-type Results (Listof ResultRow)) (struct LocalSQLNull () #:prefab) (define-type AnyVal (U String Number Boolean Char Bytes sql-timestamp LocalSQLNull)) (: pre-process-results (-> RawResults Results)) (define (pre-process-results raw-res) (map (λ([row-vec : (Vectorof Any)]) (vector-map (λ([val : Any]) (cond [(sql-null? val) (LocalSQLNull)] [else (cast val AnyVal)])) row-vec)) raw-res))

… And this works just fine in my test. My tests are in #lang typed/racket/base, they use typed/rackunit, and typed/db, and I do not use query-rows, I simply construct a list of vectors by hand, insert sql-null values, and it all works.


hoshom
2019-3-5 18:16:22

But when I import this into an untyped module


hoshom
2019-3-5 18:16:29

and pass a result from query-rows


hoshom
2019-3-5 18:16:36

It complains about sql-null


hoshom
2019-3-5 18:28:03

This is a minimal, runnable example of the thing I’m trying to get around


hoshom
2019-3-5 18:38:52

I think you people are right and I should stop using Any, ditch the LocalSQLNull thing, remove RawResults, use (Listof (Vectorof AnyVal)), and use SQL-Null from typed/db, and try and fix the resulting type errors.


samth
2019-3-5 18:39:37

@hoshom I think that’s the right approach, but if it doesn’t work out let me know


samth
2019-3-5 18:39:54

and we should change sql-null to be something that plays better with typed racket


samth
2019-3-5 18:49:55

@lexi.lambda I changed that setting


lexi.lambda
2019-3-5 18:50:17

Thank you!


hoshom
2019-3-5 19:09:52

@samth Right, thanks, I just powered through all the type errors I was getting. The thing was, I had a lot of functions that relied on occurrence typing and they were all getting messed up. They were mostly working on a union of list, a custom struct, and an AnyVal, where the else case always applied to AnyVal. And the list or custom struct could contain any of those 3 inside. But the moment I introduce SQL-Null in the union type for AnyVal they would all get messed up because the actual struct for sql-null is hidden.

The way to work around this is to add a branch that checks for sql-null before all the other branches, and simply copy whatever I was doing in the else branches.

The code’s all here, in a very work-in-progress kinda package I’m making: https://gitlab.com/hashimmm/remap/blob/master/private/grouping-v2.rkt (though at the time of writing this, it doesn’t have the fixes/changes I’m making right now)

So when I was doing this, I did understand that, and I figured that if I can use the #:struct form of require/typed, it would work, and indeed, for sql-timestamp, it all works, because if something is a list or a different struct it isn’t a sql-timestamp and TR knows that. So it all works as expected.

At the time I looked up the code for sql-null and found this had been done to make it a singleton. Wouldn’t a prefab struct achieve the same result, plus allow better interaction with TR?


samth
2019-3-5 19:10:43

A prefab struct wouldn’t make it a singleton


samth
2019-3-5 19:11:19
> (eq? #s(sql-null) #s(sql-null))
#f

hoshom
2019-3-5 19:11:40

Oh! totally did not expect that. My intuition failed me :disappointed:


samth
2019-3-5 19:11:43

the right thing from typed racket’s perspective would be to make it a transparent struct


hoshom
2019-3-5 19:12:02

I see


samth
2019-3-5 19:12:07

but that would allow people to violate the singleton invariant, maybe


samth
2019-3-5 19:12:19

I think I have a way to fix it, but I have to test it out


hoshom
2019-3-5 19:12:44

cool, I’ll check it out if I notice the change


hoshom
2019-3-5 19:17:16

Things mostly work now, but now my tests fail because check-equal? complains for the exact same reason! check-equal?: contract violation any-wrap/c: Unable to protect opaque value passed as `Any` value: #<sql-null> in: the 2nd argument of (->* (Any Any) (any/c) any/c)


lexi.lambda
2019-3-5 19:20:07

I think you want to import sql-null? with #:opaque to create a new type Sql-Null, then import sql-null with the type Sql-Null.


lexi.lambda
2019-3-5 19:20:50

(I haven’t read all the above context, so if that was already discussed, sorry.)


samth
2019-3-5 19:21:53

@hoshom unfortunately that’s a less-fixable problem with check-equal?


samth
2019-3-5 19:23:02

I think using check and equal? will work better


lexi.lambda
2019-3-5 19:30:31

@samth Why does check-equal? explode the any-wrap/c contract? I don’t totally understand, but I’m curious. I thought any-wrap/c just caused problems if you tried to use mutable state or call procedures or things like that.


samth
2019-3-5 19:31:26

@lexi.lambda it tries to wrap sql-null with a chaperone that does the exploding, but it can’t (because it’s an opqaue struct) and so it errors


lexi.lambda
2019-3-5 19:31:53

Ah, I see, that makes sense. Hence the “opaque” in the error message.


hoshom
2019-3-5 19:33:08

@samth oh, yes, that works. I’d given up for the time being, but, coool :blush:


samth
2019-3-5 19:58:27

hoshom
2019-3-5 20:10:38

@samth thanks!


alexknauth
2019-3-5 20:11:05

Another thing we could do is improve vector contracts. Typed Racket relies on different contracts for Any depending on whether its doing from “typed -> untyped” or “unyped -> typed”. The box/c contract allows those to be different, so that different contracts can be applied depending on which direction its crossing the boundary in. If the vectorof contract (and probably all the contracts for mutable data structures) allowed that in the same way, then any-wrap/c would not be an issue in places like this.


alexknauth
2019-3-5 20:12:10

(By that I mean, any-wrap/c would only become an issue if you mutated it, but not if you only read from it)


samth
2019-3-5 20:12:10

@alexknauth I don’t really see how that would change things


samth
2019-3-5 20:12:25

any-wrap/c doesn’t use box/c or vectorof


alexknauth
2019-3-5 20:12:50

I know, but the Vectorof type uses the vectorof contract


alexknauth
2019-3-5 20:13:01

and the argument to vectorof needs to be any-wrap/c because of this


samth
2019-3-5 20:13:36

I’m confused


alexknauth
2019-3-5 20:13:44

But if vectorof took two contracts, one for “getting” and one for “setting”, then the “getting” one could be any/c and only the “setting” one would have to be any-wrap/c


samth
2019-3-5 20:13:53

is the issue about using vectorof in typed code?


alexknauth
2019-3-5 20:14:17

Typed Racket’s contract-generation needs to be conservative to protect typed values


samth
2019-3-5 20:14:47

can you point to where in the code you’re talking about?


alexknauth
2019-3-5 20:15:10

This distinction between getting and setting would allow Typed Racket to be more liberal on the getting side


samth
2019-3-5 20:15:46

I still don’t understand


lexi.lambda
2019-3-5 20:15:50

I think Alex is talking about the place where untyped code calls pre-process-results with a vector in @hoshom’s original example.


lexi.lambda
2019-3-5 20:16:21

It wouldn’t solve the check-equal? problem, but it would avoid the initial issue, if I understand what Alex is saying.



samth
2019-3-5 20:17:29

ah, I understand. You’re saying that (Vectorof Any) could get translated to (vectorof any/c any-wrap/c)


alexknauth
2019-3-5 20:17:41

Yes


alexknauth
2019-3-5 20:18:06

Yes, where the “getting” side is #:covariant and the “setting” side is #:contravariant


hoshom
2019-3-6 02:58:25

What’s any-wrap/c? I sort of can’t find it


hoshom
2019-3-6 02:58:51

Is it an impersonator contract?


lexi.lambda
2019-3-6 03:16:44

It’s sadly undocumented, I think… but it’s the contract TR uses for Any (not any/c).


hoshom
2019-3-6 03:37:08

Yes, it’s undocumented; first I looked in the docs, then I searched the github repo (racket/racket) and then I posted here. Is it an impersonator contract?


lexi.lambda
2019-3-6 03:38:59

It’s a chaperone contract, I think.


hoshom
2019-3-6 03:41:44

hmm ok


dan
2019-3-6 03:45:35

hoshom
2019-3-6 03:49:22

I’m basically trying to develop better intuition around what the error meant when it said “unable to protect opaque value passed as any”. Would it be correct to say that the error occurred because of all these things: (a) the function accepts a type name that TR doesn’t know about, (b) we gave TR a predicate, saying “this is how you check the type”, (c) in an untyped module, a value is given to that function that MAY be of the accepted type, (d) because the value is opaque, and the contract isn’t flat, TR cannot deduce whether the contract has modified the value, (e) as in, TR can’t tell that maybe the value was of the accepted type but the contract messed with it, or maybe the value was not of the accepted type but the contract may have made it so


hoshom
2019-3-6 03:50:54

(f) as in, the predicate may return true or false on that value, but that may not be the same value as the one originally passed, so the result of the predicate would be invalid


hoshom
2019-3-6 03:52:47

In which case, there seems to be a way out: because if the predicate is an “eq?” check, then the result of the predicate is always valid, no?


hoshom
2019-3-6 03:55:05

thanks! Silly me, I ought to have thought to search in the typed racket repo