# How to conditional \`require\`

**URL:** <https://racket.discourse.group/t/how-to-conditional-require/435>\
**Category:** Questions & Answers\
**Created:** [December 17, 2021, 9:00am UTC](https://racket.discourse.group/t/how-to-conditional-require/435 "2021-12-17T09:00:44Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![dannypsnl](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/dannypsnl/32/917_2.png) [@dannypsnl](https://racket.discourse.group/u/dannypsnl)\
**Post date:** [December 17, 2021, 9:00am UTC](https://racket.discourse.group/t/how-to-conditional-require/435/1 "2021-12-17T09:00:44Z")

</div>

The purpose is I want to build a set of low-level LLVM bindings like

- llvm 12
- llvm 13
- llvm 14

And provides a high-level package to choose them dynamically(by detecting LLVM version on the system), does that possible with `raco` info.rkt?

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [December 17, 2021, 5:06pm UTC](https://racket.discourse.group/t/how-to-conditional-require/435/2 "2021-12-17T17:06:22Z")

</div>

In general `dynamic-require` is the way to do a conditional require.

If you're doing FFI bindings to LLVM then I think you could use the [`version` argument to `ffi-lib`](https://docs.racket-lang.org/foreign/Loading_Foreign_Libraries.html#%28def._%28%28lib._ffi%2Funsafe..rkt%29._ffi-lib%29%29)?

You can supply a list of versions, assuming you'll get the same bindings from all versions.

Otherwise I think you could make multiple calls to `ffi-lib`, one version at a time, until one succeeds. Then you know which version and can supply certain bindings or not?

Also, [here's an example from `db-lib` of calling it differently based on operating system](https://github.com/racket/db/blob/0336d2522a613e76ebf60705cea3be4c237c447e/db-lib/db/private/odbc/ffi.rkt#L84-L104).

Caveat: It's been some years since I worked with FFI, and even then it wasn't sophisticated. Other people will probably have better advice!

---

<div class="post-metadata">

**Author:** ![slaymaker1907](https://avatars.discourse-cdn.com/v4/letter/s/59ef9b/32.png) [@slaymaker1907](https://racket.discourse.group/u/slaymaker1907)\
**Post date:** [December 18, 2021, 2:17am UTC](https://racket.discourse.group/t/how-to-conditional-require/435/3 "2021-12-18T02:17:23Z")

</div>

Note that `dynamic-require` still obeys lexical scope so code outside of that scope won't have access to imported bindings. In order to do something like a conditional `dynamic-require`, you will probably need to return the bindings in a struct or something (assuming you have multiple elements being dynamically imported).

```scheme
(struct foobar (foo bar))
(define (load-foobar)
  (if some-cond
      (let ([foo (dynamic-require 'foobar-impl1 'foo)]
            [bar (dynamic-require 'foobar-impl1 'bar)])
        (foobar foo bar))
      (let ([foo (dynamic-require 'foobar-impl2 'foo)]
            [bar (dynamic-require 'foobar-impl2 'bar)])
        (foobar foo bar))))

```

Alternatively, you could have dummy implementations for everything `(define foollvm (lambda args (error 'foollvm "function not loaded)))` and then later on call `(set! foollvm foollvm-impl)`. As long as the `set!` is done in the same module as `define`, this should always work. If going this route, I recommend raising an exception if the dummy function is called before initialized rather than using `undefined` or `#f` so that errors are clear and the code fails fast.

```scheme
(define foo (lambda args (error 'foo "function not loaded")))
(define bar (lambda args (error 'bar "function not loaded")))
(if some-cond
    (let ()
      (set! foo (dynamic-require 'foobar-impl1 'foo))
      (set! bar (dynamic-require 'foobar-impl1 'bar)))
    (let ()
      (set! foo (dynamic-require 'foobar-impl2 'foo))
      (set! bar (dynamic-require 'foobar-impl2 'bar))))

```

---

<div class="post-metadata">

**Author:** ![greghendershott](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/greghendershott/32/98_2.png) [@greghendershott](https://racket.discourse.group/u/greghendershott)\
**Post date:** [December 19, 2021, 2:45pm UTC](https://racket.discourse.group/t/how-to-conditional-require/435/4 "2021-12-19T14:45:22Z")

</div>

I agree it's a good idea to think about the scenario where nothing is found.

> Note that `dynamic-require` still obeys lexical scope so code outside of that scope won't have access to imported bindings. In order to do something like a conditional `dynamic-require` , you will probably need to return the bindings in a struct or something (assuming you have multiple elements being dynamically imported).

I wouldn't say this is really about lexical scope? `dynamic-require` isn't a macro, it's just a function that returns a value. (Usually the value is a procedure value: some procedure from that module.) You can bind that returned value to a variable in all the usual ways.

For example you can just:

```scheme
(define foo (dynamic-require 'modpath 'foo))

```

as well as do things like:

```scheme
(define mods-to-try (list 'mod-path-1 'mod-path-2))

(define foo (or (for/or ([mod (in-list mods-to-try)])
                  (with-handlers ([exn:fail? (λ _ #f)])
                    (dynamic-require mod 'foo)))
                (λ _ (error 'foo "no implementation found"))))

```
