Stream: beginners

Topic: ✔ Package structuring to achieve a certain API


view this post on Zulip Hristo (Mar 20 2024 at 21:59):

Hello :wave:

I would like to structure a Roc package in a way that would enable me to call its API as per Example.roc.

tl;dr Intuitively, A and B could be viewed as standard-library interfaces, like Dict and List. However, I'd like to have a categorisation "layer" that is Ex (and such).

# Example.roc
app "example"
    packages {
        cli: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br",
        ex: "./ExamplePackage/main.roc",
    }
    imports [
        cli.Stdout,
        ex.Ex.{ B },
    ]
    provides [main] to cli

main =
    Stdout.line "Test: $(B.foo {} |> Num.toStr)"
# ExamplePackage/main.roc
package "example-package"
    exposes [A, B]
    packages {}

# ExamplePackage/Ex/A.roc
# ...
# ExamplePackage/Ex/B.roc
interface Ex.B
    exposes [foo, bar]
    imports [
        A.{ Baz },
    ]

foo = \{} -> 10
bar = \{} -> 20

# ...

The directory tree looks like the following (package root, e.g., ./ExamplePackage), but this isn't a constraint (it's rather an attempt to enable me to structure my API and enable it to be utilised as described above):

main.roc # Package main.
Ex/
    A.roc
    B.roc

I would like to be able to categorise interfaces (eg, C, D etc.) into multiple categories like Ex.

I've attempted multiple iterations to get the working. The best one so far has achieved the following result (via the package structure described above):

    imports [
        cli.Stdout,
        ex.Ex.B,
    ]
# ...
main =
    Stdout.line "Test: $(Ex.B.foo {} |> Num.toStr)"

but this isn't what my actual goal is.

When I attempt to import B via curly braces, I get an error that Ex.roc doesn't exist. This is understandable and I believe the issue is to do with my lack of knowledge, in terms of what syntax applies to my use-case. I know I could achieve this via defining A and Bin Ex.roc, in order to be able to access them in the desired way. But ideally, I'd like to have them as separate interfaces, because they come with their associated sets of exposed definitions.

Html.Attributes from the static-site-gen example seems to be similar enough, but I haven't been able to identify the kind of API access that I'm looking for there.

Thanks!

view this post on Zulip Luke Boswell (Mar 20 2024 at 22:24):

In your app, does it work if you import B like ex.Ex.B instead?

view this post on Zulip Eli Dowling (Mar 20 2024 at 22:25):

As far as I'm aware what you want (being able to import Ex.{A,B}) isn't currently possible. I don't see any reason it couldn't be but that syntax just hasn't been implemented.

view this post on Zulip Eli Dowling (Mar 20 2024 at 22:26):

I ran into this myself recently actually, it's a pain

view this post on Zulip Luke Boswell (Mar 20 2024 at 22:26):

Is it like the Internal packages, where you need to import it in Ex and then re-expose it?

view this post on Zulip Eli Dowling (Mar 20 2024 at 22:28):

Well Ex isn't actually a package, just a path.
If you want to import just A so you can do A.myFunc it's not possible. You have to import the full Ex.A and use the full Ex.A.myFunc

view this post on Zulip Hristo (Mar 20 2024 at 22:29):

Hi @Luke Boswell

In your app, does it work if you import B like ex.Ex.B instead?

Yes, it does.

Is it like the Internal packages, where you need to import it in Ex and then re-expose it?

Not necessarily. I'd like to utilise Ex (and other similar "categories") for categorisation.

Thank you for looking into this!

view this post on Zulip Hristo (Mar 20 2024 at 22:30):

Hi @Eli Dowling,

Yes, that's been my conclusion so far as well. Just wanted to double-check if I'm not missing something.

Thanks for your time, too!

view this post on Zulip Eli Dowling (Mar 20 2024 at 22:31):

Honestly one could make a strong argument that importing Ex.A should allow usingA.myFUnc, and that should you want to useEx.A.myFunc you should simply import Ex

view this post on Zulip Luke Boswell (Mar 20 2024 at 22:36):

Agus is working on the module changes. He gave a nice demo in the online meetup, first talk. I'm not sure it specifically addresses this issue, but just thought I'd mention in case you're interested in the new syntax.

view this post on Zulip Eli Dowling (Mar 20 2024 at 22:36):

There is some chance this will be fixed when module params and the module syntax change is finished.
@Agus Zubiaga Is that possible?

view this post on Zulip Eli Dowling (Mar 20 2024 at 22:36):

HAahaha well timed :joy:

view this post on Zulip Luke Boswell (Mar 20 2024 at 22:37):

Lol, https://drive.google.com/file/d/1j2V2CeDN84MjfWPtcLaagQKcCt2qnqum/view?usp=drivesdk

view this post on Zulip Luke Boswell (Mar 20 2024 at 22:37):

^^ video link

view this post on Zulip Hristo (Mar 20 2024 at 22:43):

Thank you!
I did listen to the talk (in the background) during work the other day! I'll re-watch it properly to see if it'll enable something that'be closer to the desired use-case.

view this post on Zulip Notification Bot (Mar 20 2024 at 22:43):

Hristo has marked this topic as resolved.


Last updated: Jul 06 2025 at 12:14 UTC