Best way to handle different versions of Racket?

83 views
Skip to first unread message

Siddhartha Kasivajhula

unread,
Mar 30, 2020, 2:49:45 PM3/30/20
to Racket Users
Hi there,
Is there a standard/recommended way to handle multiple versions of Racket in library code?

For instance, this handy utility was added in a recent version of Racket:


I'd like to use it in my library code but that would probably mean that users with an older version of Racket wouldn't be able to use the library, is that right? I'm tempted to add something like:

(require version/utils)
(define string-append
  (if (version<? (version) "7.5.0.14")
      (compose string->immutable-string string-append)
      string-append-immutable))

... at the top of the module. Is this advisable? Or is there a better, maybe more raco-friendly way?

Thanks,
-Sid


Sorawee Porncharoenwase

unread,
Mar 30, 2020, 3:01:11 PM3/30/20
to Siddhartha Kasivajhula, Racket Users

Your code would not work because prior 7.5.0.14, there’s no string-append-immutable, so the use of string-append-immutable in the else branch will result in an unbound id error.

Instead, use https://docs.racket-lang.org/version-case/index.html which will run the “if” at compile-time, making the "unbound id" go away at compile-time.

Another problem is that when you define string-append (or even string-append-immutable), it will shadow Racket’s string-append (or string-append-immutable). You might want to do something like this instead:

(define @string-append-immutable ... now you can use string-append-immutable here ...)
(provide (rename-out [@string-append-immutable string-append-immutable]))


--
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/CACQBWFkRahhtoXKUbpcJ%2BHpYwq5FBU85Ze_NGkEntXX3kTD01g%40mail.gmail.com.

Sorawee Porncharoenwase

unread,
Mar 30, 2020, 3:11:56 PM3/30/20
to Siddhartha Kasivajhula, Racket Users

Is there any reason to use Racket’s string-append-immutable though? It might be simpler to just:

(define string-append-immutable
  (compose string->immutable-string string-append))

(provide string-append-immutable)

since you need to define it anyway for the versions prior 7.5.0.14.

Siddhartha Kasivajhula

unread,
Mar 30, 2020, 3:17:32 PM3/30/20
to Sorawee Porncharoenwase, Racket Users
That looks great, thanks! Re: shadowing, I don't plan to re-provide string-append-immutable -- only use it internally within the module, so shadowing should be OK, right?
Re: reason to use it - performance. I'm applying the string-append operation in a pairwise way over input sequences, and re-converting to immutable at each step appears to have a measurable cost.

Sorawee Porncharoenwase

unread,
Mar 30, 2020, 3:29:33 PM3/30/20
to Siddhartha Kasivajhula, Racket Users

The problem with shadowing is more than that. Suppose you somehow want to shadow add1 by making it add 2 instead.

(define add1 (compose add1 add1))

However, this will not work, resulting in the following error:

add1: undefined;
 cannot reference an identifier before its definition

because blue add1 refers to red add1, not Racket’s add1.

So you really need to either rename Racket’s add1 to something else, or define your add1 with another name. The first approach would be something like:

(require (only-in racket [add1 @add1]))
(define add1 (compose @add1 @add1))

and the second approach would be something like:

(define @add1 (compose add1 add1))

Siddhartha Kasivajhula

unread,
Mar 30, 2020, 4:04:21 PM3/30/20
to Sorawee Porncharoenwase, Racket Users
Ah right, that makes sense :)

Ben Greenman

unread,
Mar 30, 2020, 10:52:14 PM3/30/20
to Racket Users
On 3/30/20, Siddhartha Kasivajhula <skas...@gmail.com> wrote:
> Hi there,
> Is there a standard/recommended way to handle multiple versions of Racket
> in library code?

If you're planning to ship the library as a package, you can also:

1. make 2 versions of the library (maybe as two branches in the same git repo)
2. add a version exception on pkgs.racket-lang.org

https://docs.racket-lang.org/pkg/getting-started.html#(part._.Version_.Exceptions)

Greg Hendershott

unread,
Apr 3, 2020, 9:54:16 AM4/3/20
to Racket Users
Is there a standard/recommended way to handle multiple versions of Racket in library code?

1. You can use dynamic-require to see if the new thing is actually provided by a module, and in a with-handlers clause substitute your not-found, default behavior.

If you do that frequently you could wrap that in a little macro like this:


2. You could run tests using Travis CI or similar, against multiple/older versions of Racket.  For example:



Siddhartha Kasivajhula

unread,
Apr 4, 2020, 8:31:45 PM4/4/20
to Greg Hendershott, Racket Users
These sound like three different, alternative ways to do it! Nice to know there are options which presumably each have their merits.

@Greg I'm using your Makefile template already :)


--
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages