Unfamiliar syntax + trying to debug an existing binding lib

Exploring the existing Jotai Re-Script bindings and found a potential bug. A detailed report can be found at [BUG]: TypeError when creating a derived atom from a derived atom · Issue #9 · gaku-sei/re-jotai · GitHub but the short version is:

  • You can define a reactive atom with a value that is readable and writable
  • You can define a derived value that is readable from a readable and writable atom
  • You CANNOT define a derived value from another readable derived value

In the original Jotai implementation, it is intended to support Readable → Readable derivatives. A quick test can be found at: jotai-demo (forked) - CodeSandbox.

I’m not very confident in my ReScript so upon looking around I have a suspect:

Specifically I’m thinking it’s the [> Permissions.r] part that seems to work as expected when you provide a default readable + writable as the source to get but not a readable.

Where I got stuck is I don’t recognize that syntax, despite my efforts I was unable to find a similar sample mentioned in the docs. I think it’s part of the destructuring\pattern-matching syntax but I’m not quite sure? Seems to act as some kind of guard?

I would like to know more about this so I can look into fixing it, even if the author is able to patch it before I can find a solution, it seems like a good learning opportunity. Is this something I just overlooked in the docs or some implied combination of the pre-existing concepts?

What syntax? [> Permissions.r]?

This is a polymorphic variant type with a lower bound constraint as described in the docs here.

1 Like

Ah thank you! I am not sure how I missed that, but I did :flushed:

Now I understand it: It’s saying it as a minimum accepts Permissions.r but additional ones are fine because it’s open!

Turns out that it wasn’t the problem. It’s because of the following part:

let get = (type value, get: getter, atom: t<value, 'value => 'value, [> Permissions.r]>): value =>

Where the atom arg is defined as t<value, 'value => 'value, [> Permissions.r]> where that middle generic param is the setter which is not required for only readable atoms.

I was able to get tests to pass by changing it to the following:
atom: t<value, _, [> Permissions.r]>

But I wonder if that has unforeseeable consequences being too relaxed there?

As of now I’m thinking the solution would be to create a variant type for the writer:

type void

type writer<'value> = void | ('value => 'value)

But I’m getting an error that it has no idea what | means there. Maybe it should be a smarter type where if it’s readable it doesn’t care about the writer param, otherwise it should be a function that takes a value and returns a value like the original?

I don’t think you want a variant type, because then you would have to do something along the lines of

type writer<'v> =
  | Void
  | Fn('v => 'v)

which defeats the purpose of what type void means. The key is that void has no constructor and thus is uninhabited. There’s no way to construct void in the program, so it can used as a placeholder for something that’s nonsensical.

1 Like

That’s helpful. In that case I’m not sure what a better solution would look like than relaxing the requirement.