Stream: beginners

Topic: interface question


view this post on Zulip Artur Swiderski (Dec 11 2023 at 15:40):

Could I pass Types defined in interface to be seen in other files ? What is the syntax for that?

view this post on Zulip Fletch Canny (Dec 11 2023 at 15:53):

Hi! Yes you can do that!
In your interface file:

interface SomeInterface
  exposes [SomeType]
  imports []

SomeType : [SomeTag]

in the file you wish to use it you just need to specify in the imports section what you want to use

imports [SomeInterface.{SomeType}]
...
value : SomeType
value = SomeTag

Although you can qualify the type when you use it instead

imports [SomeInterface]
...
value : SomeInterface.SomeType
value = SomeTag

You can also hide the implementation using opaque types, which you can read more about in the docs-
https://www.roc-lang.org/tutorial#opaque-types

hope that helped!

view this post on Zulip Artur Swiderski (Dec 11 2023 at 19:15):

btw. could you produce example of that

You can prevent that data needs to be checked multiple times. For example, you can create an opaque NonEmptyList from a List after you've checked it. Now all functions that you pass this NonEmptyList to do not need to handle the empty list case.

I don't get it

view this post on Zulip Fletch Canny (Dec 12 2023 at 04:04):

It's about implementation hiding-
if you've ever used an OO language like Java / C# you would use an opaque type for the same reason you use private variables.
In Elm it would be like exposing SomeType instead of SomeType(..).

The point of an opaque type is that you can only examine it's internals within the file that created it. So if I want to do something with a non-empty list value, I could create an opaque type which can only be interfaced with in safe ways by guaranteeing that the list is never empty, even though a NonEmptyList type would be internally represented as a List.

view this post on Zulip Anton (Dec 12 2023 at 11:12):

Elm has a nonempty list package that you could copy in Roc. With a package like that you can use the fromList function at the start to check if your list is empty. If it's not, you now have a NonEmpty (=list). You can now get for example the last element, and that function is guaranteed to return an element, so you no longer need to deal with a Result type for the empty list case.

view this post on Zulip Declan Joseph Maguire (Dec 12 2023 at 11:19):

I wonder if there's a way to generalise that pattern? There's lots of functions that can error purely because of some degenerate case, where it would be more useful to rule out from the start rather than check at every stage.

view this post on Zulip Anton (Dec 12 2023 at 11:22):

Dependent types is one solution, but that's also complex to implement.

view this post on Zulip Declan Joseph Maguire (Dec 12 2023 at 11:31):

I think some long conversation has been had about that, so I knew that was a possibility. If I remember, the answer was a resounding "maybe, possibly, someday, if a bunch of problems it'd cause could be solved, but not now". I was just curious if there were some trick that wouldn't require altering the type system.

view this post on Zulip Richard Feldman (Dec 12 2023 at 12:03):

there's a trick involving a type variable trick similar to what we do with Num

view this post on Zulip Richard Feldman (Dec 12 2023 at 12:05):

e.g. something like this:

List elem emptiness := ...

PotentiallyEmptyList elem : BaseList elem [CouldBeEmpty]
NonEmptyList elem emptiness : List elem emptiness

but I don't like what that would do to the ergonomics of lists :big_smile:

view this post on Zulip Declan Joseph Maguire (Dec 12 2023 at 12:32):

Maybe it'd be worth figuring out if there'd be a way to make that ergonomic in the future, because it'd certainly be useful. But that sounds like a future-if-ever-problem.

view this post on Zulip Johan Lövgren (Dec 12 2023 at 12:36):

Anton said:

Elm has a nonempty list package that you could copy in Roc. With a package like that you can use the fromList function at the start to check if your list is empty. If it's not, you now have a NonEmpty (=list). You can now get for example the last element, and that function is guaranteed to return an element, so you no longer need to deal with a Result type for the empty list case.

I started implementing a type like this. Still a work in progress though: https://github.com/Subtlesplendor/roc-data/blob/main/package/NonEmpty.roc


Last updated: Jul 05 2025 at 12:14 UTC