# Define forms for library API

**URL:** <https://racket.discourse.group/t/define-forms-for-library-api/317>\
**Category:** Questions & Answers\
**Created:** [November 30, 2021, 1:42pm UTC](https://racket.discourse.group/t/define-forms-for-library-api/317 "2021-11-30T13:42:17Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![rscho](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/rscho/32/726_2.png) [@rscho](https://racket.discourse.group/u/rscho)\
**Post date:** [November 30, 2021, 1:42pm UTC](https://racket.discourse.group/t/define-forms-for-library-api/317/1 "2021-11-30T13:42:17Z")

</div>

Hi,

I'm making a library where I have the following macro:

```scheme
(define-syntax (define-dataframe stx)
    (syntax-case stx ()
      [(_ name args ...)
       (with-syntax ([name-string (symbol->string (format-symbol "~a" #'name))])
         #'(begin (define name (make-dataframe name-string args ...))
                  (will-register (database-will-executor) name-string database-garbage-collect!)))]))

```

An alternative technique would be to hijack the main `define` macro and add a clause that does what I want. But that might come back to bite me later? What is the better practice for library APIs?

---

<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:** [November 30, 2021, 2:11pm UTC](https://racket.discourse.group/t/define-forms-for-library-api/317/2 "2021-11-30T14:11:05Z")

</div>

Even if a macro works as a replacement for `define` (like say `trace-define`) I'd recommend providing it with a distinct name (as does `trace-define`).

In other words, let users decide if they want to rename it to `define` when they `require` it.

* * *

But also, do you need a definition macro at all? Couldn't `make-dataframe` (or some new function that wraps it) handle the will registration? That way users could use plain old `define` (or any binding form).

---

<div class="post-metadata">

**Author:** ![rscho](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/rscho/32/726_2.png) [@rscho](https://racket.discourse.group/u/rscho)\
**Post date:** [November 30, 2021, 2:26pm UTC](https://racket.discourse.group/t/define-forms-for-library-api/317/3 "2021-11-30T14:26:17Z")

</div>

Thanks for the input. The (perhaps naive) reason I wrote this macro was to allow doing `(define-dataframe df ...` instead of `(make-dataframe "df" ...` to yield a dataframe identifier, which is closer to the usual use of `define`. I agree that the will registration does not warrant a macro.

Perhaps it would be best to provide the user with both `define-dataframe` and `make-dataframe`?

---

<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:** [November 30, 2021, 2:59pm UTC](https://racket.discourse.group/t/define-forms-for-library-api/317/4 "2021-11-30T14:59:15Z")

</div>

> [@rscho](#):
>
> Perhaps it would be best to provide the user with both `define-dataframe` and `make-dataframe` ?

That sounds reasonable.

To be clear, I was only offering my opinion on your question about what's good for a library API. I think for that:

- Make things available as plain functions when possible, or at least in both flavors (e.g. `with-foo` macro and `call-with-foo` procedure flavors).
- For least surprise, don't supply things named to replace "standard" things, unless maybe that is the main point of the library. (Although even then, e.g. `racket/trace` avoids this.)

But within the private implementation of a library or project, of course it can make sense to use more "surprising" or "ambitious" macros or replacements.

Anyway that is just my opinion, you may get better opinions from other people!
