xarxziux
2019-2-5 10:37:34

I’m trying to use the Gregor library in a Typed Racket project, but I can’t figure out the correct syntax for typing it. A minimalistic untyped file for printing the current date could look like this:

#lang racket
(require gregor)
(displayln (~t (today) "yyyy-MM-dd"))

This displays “2019–02–05” as expected. A crude attempt to convert this to typed Racket is this:

#lang typed/racket
(require/typed gregor
               [~t (Any String -> String)]
               [today (-> Any)]
               )
(displayln (~t (today) "yyyy-MM-dd"))

But this gives the following error message:

~t: contract violation
  any-wrap/c: Unable to protect opaque value passed as `Any`
  value: #<date 2019-02-05>
  in: the 1st argument of
      (-> Any any/c String)
  contract from: (interface for ~t)

I can’t find any explanation of what this means. I’ve also tried a few other variations on this, but to no avail.

What I think I need is to define the date struct within the Gregor library (as per https://docs.racket-lang.org/ts-guide/typed-untyped-interaction.html), but the docs don’t explain how to do that. Does anyone know what I need to do here?


alexknauth
2019-2-5 14:29:23

There are two strategies I know of (that are type-safe by default)


alexknauth
2019-2-5 14:29:46
  1. Use an #:opaque type declaration in the require/typed form

alexknauth
2019-2-5 14:30:05
  1. Use a #:struct declaration in the require/typed form

alexknauth
2019-2-5 14:30:53

(1) can look like this: #lang typed/racket (require/typed gregor [#:opaque Date date?] [~t (Date String -> String)] [today (-> Date)]) (displayln (~t (today) "yyyy-MM-dd"))


alexknauth
2019-2-5 14:34:58

(2) only works when the library exposes the struct to you, which gregor doesn’t


xarxziux
2019-2-5 15:53:17

Sweet. Got it working. Thanks a lot!


jaz
2019-2-5 20:17:56

@xarxziux On a related note: I often regret making the time zone argument to today (and other functions) optional. I think programmers routinely forget that “today” is an indexical term.


notjack
2019-2-5 20:24:49

Google is currently making an effort internally to fix all date and time bugs in all Java code and so far the biggest cause of them is implicitly relying on the system default clock and time zone


tim
2019-2-5 20:25:59

@tim has joined the channel


notjack
2019-2-5 20:26:00

It sneaks global mutable state into places, and if that’s not bad enough the state has confusing and unintuitive semantics


jaz
2019-2-5 20:27:11

It certainly does


notjack
2019-2-5 20:31:01

Interestingly the other main problem is APIs and libraries that don’t support nanosecond precision


jaz
2019-2-5 20:33:45

That is interesting. I haven’t written Java in a long time, but, while I wasn’t especially surprised to see that java.util.Date only has millisecond precision, I was surprised that Joda was the same. The newer java.time stuff has nanosecond precision, I believe (as Gregor does).


philip.mcgrath
2019-2-5 21:10:02

Running the following program raises a use-before-initialization error for make-foo/c when evaluating the (invoke-unit foo@). I suspect this is a bug (maybe related to https://github.com/racket/racket/issues/1652), but does anyone know if it is supposed to work, or if there’s some other way to achieve this? #lang racket (define-signature foo^ [foo? (define-values-for-export [make-foo/c] (-> foo?)) make-foo/c (contracted [make-foo make-foo/c])]) (define-unit foo@ (import) (export foo^) (define (foo? x) (eq? x 'foo)) (define (make-foo) 'foo)) (invoke-unit foo@)


notjack
2019-2-5 21:18:03

Yup. Migrating code to jave.time is a big part of the bug fix effort.


philip.mcgrath
2019-2-5 21:32:46

xarxziux
2019-2-5 21:44:24

I only need it to parse invoice dates pulled from a CSV file and get the difference between them. I doubt it’ll be an issue. Your library works just fine for me. :+1: